Skip to content

Commit 34d9624

Browse files
authored
Merge pull request #60671 from hborla/invalid-existential-access
[Diagnostics] Improve diagnostics for invalid type access on existential types.
2 parents 0127c47 + cd7bc86 commit 34d9624

File tree

7 files changed

+53
-19
lines changed

7 files changed

+53
-19
lines changed

include/swift/AST/DiagnosticsSema.def

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2465,11 +2465,13 @@ WARNING(append_interpolation_access_control,none,
24652465

24662466
// Protocols and existentials
24672467
ERROR(assoc_type_outside_of_protocol,none,
2468-
"associated type %0 can only be used with a concrete type or "
2469-
"generic parameter base", (DeclNameRef))
2468+
"cannot access associated type %0 from %1; use a concrete type or "
2469+
"generic parameter base instead",
2470+
(DeclNameRef, Type))
24702471
ERROR(typealias_outside_of_protocol,none,
2471-
"type alias %0 can only be used with a concrete type or "
2472-
"generic parameter base", (DeclNameRef))
2472+
"cannot access type alias %0 from %1; use a concrete type or "
2473+
"generic parameter base instead",
2474+
(DeclNameRef, Type))
24732475

24742476
ERROR(objc_protocol_inherits_non_objc_protocol,none,
24752477
"@objc protocol %0 cannot refine non-@objc protocol %1", (Type, Type))

lib/Sema/CSDiagnostics.cpp

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4294,7 +4294,8 @@ bool AllowTypeOrInstanceMemberFailure::diagnoseAsError() {
42944294
}
42954295
}
42964296

4297-
if (BaseType->is<AnyMetatypeType>() && !Member->isStatic()) {
4297+
bool isStaticOrTypeMember = Member->isStatic() || isa<TypeDecl>(Member);
4298+
if (BaseType->is<AnyMetatypeType>() && !isStaticOrTypeMember) {
42984299
auto instanceTy = BaseType;
42994300

43004301
if (auto *AMT = instanceTy->getAs<AnyMetatypeType>()) {
@@ -4402,10 +4403,10 @@ bool AllowTypeOrInstanceMemberFailure::diagnoseAsError() {
44024403
// static members doesn't make a whole lot of sense
44034404
if (isa<TypeAliasDecl>(Member)) {
44044405
Diag.emplace(
4405-
emitDiagnostic(diag::typealias_outside_of_protocol, Name));
4406+
emitDiagnostic(diag::typealias_outside_of_protocol, Name, instanceTy));
44064407
} else if (isa<AssociatedTypeDecl>(Member)) {
44074408
Diag.emplace(
4408-
emitDiagnostic(diag::assoc_type_outside_of_protocol, Name));
4409+
emitDiagnostic(diag::assoc_type_outside_of_protocol, Name, instanceTy));
44094410
} else if (isa<ConstructorDecl>(Member)) {
44104411
Diag.emplace(
44114412
emitDiagnostic(diag::construct_protocol_by_name, instanceTy));

lib/Sema/TypeCheckType.cpp

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,7 @@ Type TypeResolution::resolveDependentMemberType(
126126
// FIXME(ModQual): Reject qualified names immediately; they cannot be
127127
// dependent member types.
128128
Identifier refIdentifier = ref->getNameRef().getBaseIdentifier();
129+
ASTContext &ctx = DC->getASTContext();
129130

130131
switch (stage) {
131132
case TypeResolutionStage::Structural:
@@ -146,8 +147,6 @@ Type TypeResolution::resolveDependentMemberType(
146147
// Record the type we found.
147148
ref->setValue(nestedType, nullptr);
148149
} else {
149-
ASTContext &ctx = DC->getASTContext();
150-
151150
// Resolve the base to a potential archetype.
152151
// Perform typo correction.
153152
TypoCorrectionResults corrections(ref->getNameRef(), ref->getNameLoc());
@@ -188,6 +187,25 @@ Type TypeResolution::resolveDependentMemberType(
188187

189188
auto *concrete = ref->getBoundDecl();
190189

190+
if (auto concreteBase = genericSig->getConcreteType(baseTy)) {
191+
bool hasUnboundOpener = !!getUnboundTypeOpener();
192+
switch (TypeChecker::isUnsupportedMemberTypeAccess(concreteBase, concrete,
193+
hasUnboundOpener)) {
194+
case TypeChecker::UnsupportedMemberTypeAccessKind::TypeAliasOfExistential:
195+
ctx.Diags.diagnose(ref->getNameLoc(),
196+
diag::typealias_outside_of_protocol,
197+
ref->getNameRef(), concreteBase);
198+
break;
199+
case TypeChecker::UnsupportedMemberTypeAccessKind::AssociatedTypeOfExistential:
200+
ctx.Diags.diagnose(ref->getNameLoc(),
201+
diag::assoc_type_outside_of_protocol,
202+
ref->getNameRef(), concreteBase);
203+
break;
204+
default:
205+
break;
206+
};
207+
}
208+
191209
// If the nested type has been resolved to an associated type, use it.
192210
if (auto assocType = dyn_cast<AssociatedTypeDecl>(concrete)) {
193211
return DependentMemberType::get(baseTy, assocType);
@@ -1656,12 +1674,12 @@ static Type resolveNestedIdentTypeComponent(TypeResolution resolution,
16561674

16571675
case TypeChecker::UnsupportedMemberTypeAccessKind::TypeAliasOfExistential:
16581676
diags.diagnose(comp->getNameLoc(), diag::typealias_outside_of_protocol,
1659-
comp->getNameRef());
1677+
comp->getNameRef(), parentTy);
16601678
return ErrorType::get(ctx);
16611679

16621680
case TypeChecker::UnsupportedMemberTypeAccessKind::AssociatedTypeOfExistential:
16631681
diags.diagnose(comp->getNameLoc(), diag::assoc_type_outside_of_protocol,
1664-
comp->getNameRef());
1682+
comp->getNameRef(), parentTy);
16651683
return ErrorType::get(ctx);
16661684
}
16671685

test/decl/typealias/associated_types.swift

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,16 +4,16 @@ protocol BaseProto {
44
associatedtype AssocTy
55
}
66
var a: BaseProto.AssocTy = 4
7-
// expected-error@-1{{associated type 'AssocTy' can only be used with a concrete type or generic parameter base}}
7+
// expected-error@-1{{cannot access associated type 'AssocTy' from 'BaseProto'; use a concrete type or generic parameter base instead}}
88

99
var a = BaseProto.AssocTy.self
10-
// expected-error@-1{{associated type 'AssocTy' can only be used with a concrete type or generic parameter base}}
10+
// expected-error@-1{{cannot access associated type 'AssocTy' from 'BaseProto'; use a concrete type or generic parameter base instead}}
1111

1212
protocol DerivedProto : BaseProto {
1313
func associated() -> AssocTy // no-warning
1414

1515
func existential() -> BaseProto.AssocTy
16-
// expected-error@-1{{associated type 'AssocTy' can only be used with a concrete type or generic parameter base}}
16+
// expected-error@-1{{cannot access associated type 'AssocTy' from 'BaseProto'; use a concrete type or generic parameter base instead}}
1717
}
1818

1919

test/decl/typealias/protocol.swift

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -176,8 +176,8 @@ struct T5 : P5 {
176176
var a: P5.T1 // OK
177177

178178
// Invalid -- cannot represent associated type of existential
179-
var v2: P5.T2 // expected-error {{type alias 'T2' can only be used with a concrete type or generic parameter base}}
180-
var v3: P5.X // expected-error {{type alias 'X' can only be used with a concrete type or generic parameter base}}
179+
var v2: P5.T2 // expected-error {{cannot access type alias 'T2' from 'P5'; use a concrete type or generic parameter base instead}}
180+
var v3: P5.X // expected-error {{cannot access type alias 'X' from 'P5'; use a concrete type or generic parameter base instead}}
181181

182182
// Unqualified reference to typealias from a protocol conformance
183183
var v4: T1 // OK
@@ -188,7 +188,20 @@ struct T5 : P5 {
188188
var v7: T5.T2 // OK
189189

190190
var v8 = P6.A.self
191-
var v9 = P6.B.self // expected-error {{type alias 'B' can only be used with a concrete type or generic parameter base}}
191+
var v9 = P6.B.self // expected-error {{cannot access type alias 'B' from 'P6'; use a concrete type or generic parameter base instead}}
192+
193+
var v10 = (any P6).A.self
194+
var v11 = (any P6).B.self // expected-error {{cannot access type alias 'B' from 'any P6'; use a concrete type or generic parameter base instead}}
195+
196+
struct Generic<T> {
197+
func okay(value: T.A) where T == any P6 {}
198+
199+
func invalid1(value: T.B) where T == any P6 {}
200+
// expected-error@-1 {{cannot access type alias 'B' from 'any P6'; use a concrete type or generic parameter base instead}}
201+
202+
func invalid2(value: T.A) where T == any P5 {}
203+
// expected-error@-1 {{cannot access associated type 'A' from 'any P5'; use a concrete type or generic parameter base instead}}
204+
}
192205
}
193206

194207
// Unqualified lookup finds typealiases in protocol extensions

test/type/subclass_composition.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -322,7 +322,7 @@ func dependentMemberTypes<T : BaseIntAndP2>(
322322
_: T.FullyConcrete,
323323

324324
_: BaseIntAndP2.DependentInConcreteConformance, // FIXME expected-error {{}}
325-
_: BaseIntAndP2.DependentProtocol, // expected-error {{type alias 'DependentProtocol' can only be used with a concrete type or generic parameter base}}
325+
_: BaseIntAndP2.DependentProtocol, // expected-error {{cannot access type alias 'DependentProtocol' from 'BaseIntAndP2' (aka 'Base<Int> & P2'); use a concrete type or generic parameter base instead}}
326326
_: BaseIntAndP2.DependentClass,
327327
_: BaseIntAndP2.FullyConcrete) {}
328328

validation-test/compiler_crashers_2_fixed/0159-rdar40009245.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,5 +4,5 @@ protocol P {
44
associatedtype A : P where A.X == Self
55
// expected-error@-1{{'X' is not a member type of type 'Self.A'}}
66
associatedtype X : P where P.A == Self
7-
// expected-error@-1{{associated type 'A' can only be used with a concrete type or generic parameter base}}
7+
// expected-error@-1{{cannot access associated type 'A' from 'P'; use a concrete type or generic parameter base instead}}
88
}

0 commit comments

Comments
 (0)