Skip to content

Commit 290701c

Browse files
committed
Sema: Ban shadowing generic parameters from outer scopes
Code like that is usually indicative of programmer error, and does not round-trip through module interface files since there is no source syntax to refer to an outer generic parameter. For source compatibility this is a warning, but becomes an error with -swift-version 6. Fixes rdar://problem/108385980 and #62767.
1 parent 8202acb commit 290701c

24 files changed

+133
-51
lines changed

include/swift/AST/DiagnosticsSema.def

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2783,6 +2783,10 @@ ERROR(requires_generic_params_made_equal,none,
27832783
ERROR(requires_generic_param_made_equal_to_concrete,none,
27842784
"same-type requirement makes generic parameter %0 non-generic",
27852785
(Type))
2786+
ERROR(shadowed_generic_param,none,
2787+
"generic parameter %0 shadows generic parameter from outer scope with the same name",
2788+
(DeclName))
2789+
27862790
ERROR(recursive_decl_reference,none,
27872791
"%0 %1 references itself", (DescriptiveDeclKind, DeclBaseName))
27882792
ERROR(recursive_generic_signature,none,

lib/Sema/TypeCheckDeclPrimary.cpp

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -454,11 +454,10 @@ static void diagnoseDuplicateDecls(T &&decls) {
454454
other->diagnose(diag::invalid_redecl_prev, other->getName());
455455
});
456456

457-
// Mark the decl as invalid, unless it's a GenericTypeParamDecl, which is
458-
// expected to maintain its type of GenericTypeParamType.
459-
// This is needed to avoid emitting a duplicate diagnostic when running
460-
// redeclaration checking in the case where the VarDecl is part of the
461-
// enclosing context, e.g `let (x, x) = (0, 0)`.
457+
// Mark the decl as invalid. This is needed to avoid emitting a
458+
// duplicate diagnostic when running redeclaration checking in
459+
// the case where the VarDecl is part of the enclosing context,
460+
// e.g `let (x, x) = (0, 0)`.
462461
if (!isa<GenericTypeParamDecl>(current))
463462
current->setInvalid();
464463
}
@@ -492,7 +491,7 @@ static void checkGenericParams(GenericContext *ownerCtx) {
492491
[](Requirement, RequirementRepr *) { return false; });
493492

494493
// Check for duplicate generic parameter names.
495-
diagnoseDuplicateDecls(*genericParams);
494+
TypeChecker::checkShadowedGenericParams(ownerCtx);
496495
}
497496

498497
template <typename T>

lib/Sema/TypeCheckGeneric.cpp

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -498,6 +498,63 @@ void TypeChecker::checkReferencedGenericParams(GenericContext *dc) {
498498
}
499499
}
500500

501+
/// Ensure we don't re-declare any generic parameters in the current scope,
502+
/// or shadow a generic parameter from an outer scope.
503+
void TypeChecker::checkShadowedGenericParams(GenericContext *dc) {
504+
// Collect all outer generic parameters for lookup.
505+
llvm::SmallDenseMap<Identifier, GenericTypeParamDecl *, 4> genericParamDecls;
506+
for (auto *parentDC = dc->getParent(); parentDC != nullptr;
507+
parentDC = parentDC->getParentForLookup()) {
508+
if (auto *extensionDecl = dyn_cast<ExtensionDecl>(parentDC)) {
509+
parentDC = extensionDecl->getExtendedNominal();
510+
511+
// This can happen with invalid code.
512+
if (parentDC == nullptr)
513+
return;
514+
}
515+
if (auto *parentDecl = parentDC->getAsDecl()) {
516+
if (auto *parentGeneric = parentDecl->getAsGenericContext()) {
517+
if (auto *genericParamList = parentGeneric->getGenericParams()) {
518+
for (auto *genericParamDecl : genericParamList->getParams()) {
519+
if (genericParamDecl->isOpaqueType())
520+
continue;
521+
genericParamDecls[genericParamDecl->getName()] = genericParamDecl;
522+
}
523+
}
524+
}
525+
}
526+
}
527+
528+
for (auto *genericParamDecl : dc->getGenericParams()->getParams()) {
529+
if (genericParamDecl->isOpaqueType() || genericParamDecl->isImplicit())
530+
continue;
531+
532+
auto found = genericParamDecls.find(genericParamDecl->getName());
533+
if (found != genericParamDecls.end()) {
534+
auto *existingParamDecl = found->second;
535+
536+
if (existingParamDecl->getDeclContext() == dc) {
537+
genericParamDecl->diagnose(
538+
diag::invalid_redecl,
539+
genericParamDecl->getName());
540+
} else {
541+
genericParamDecl->diagnose(
542+
diag::shadowed_generic_param,
543+
genericParamDecl->getName()).warnUntilSwiftVersion(6);
544+
}
545+
546+
if (existingParamDecl->getLoc()) {
547+
existingParamDecl->diagnose(diag::invalid_redecl_prev,
548+
existingParamDecl->getName());
549+
}
550+
551+
continue;
552+
}
553+
554+
genericParamDecls[genericParamDecl->getName()] = genericParamDecl;
555+
}
556+
}
557+
501558
///
502559
/// Generic types
503560
///

lib/Sema/TypeChecker.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -500,6 +500,10 @@ void checkProtocolSelfRequirements(ValueDecl *decl);
500500
/// declaration's type, otherwise we have no way to infer them.
501501
void checkReferencedGenericParams(GenericContext *dc);
502502

503+
/// Ensure we don't re-declare any generic parameters in the current scope,
504+
/// or shadow a generic parameter from an outer scope.
505+
void checkShadowedGenericParams(GenericContext *dc);
506+
503507
/// Diagnose a requirement failure.
504508
///
505509
/// \param errorLoc The location at which an error shall be emitted.

test/AutoDiff/Sema/derivative_attr_type_checking.swift

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -496,7 +496,7 @@ extension Struct {
496496
}
497497

498498
// expected-note @+1 {{candidate subscript does not have a setter}}
499-
subscript<T: Differentiable>(x: T) -> T { x }
499+
subscript<U: Differentiable>(x: U) -> U { x }
500500
}
501501
extension Struct where T: Differentiable & AdditiveArithmetic {
502502
@derivative(of: subscript.get)
@@ -534,14 +534,14 @@ extension Struct where T: Differentiable & AdditiveArithmetic {
534534
}
535535

536536
@derivative(of: subscript(_:).get, wrt: self)
537-
func vjpSubscriptGenericGetter<T: Differentiable>(x: T) -> (value: T, pullback: (T.TangentVector) -> TangentVector) {
537+
func vjpSubscriptGenericGetter<U: Differentiable>(x: U) -> (value: U, pullback: (U.TangentVector) -> TangentVector) {
538538
return (x, { _ in .zero })
539539
}
540540

541541
// expected-error @+2 {{a derivative already exists for '_'}}
542542
// expected-note @-6 {{other attribute declared here}}
543543
@derivative(of: subscript(_:), wrt: self)
544-
func vjpSubscriptGeneric<T: Differentiable>(x: T) -> (value: T, pullback: (T.TangentVector) -> TangentVector) {
544+
func vjpSubscriptGeneric<U: Differentiable>(x: U) -> (value: U, pullback: (U.TangentVector) -> TangentVector) {
545545
return (x, { _ in .zero })
546546
}
547547

@@ -576,8 +576,8 @@ extension Struct where T: Differentiable & AdditiveArithmetic {
576576
// Error: original subscript has no setter.
577577
// expected-error @+1 {{referenced declaration 'subscript(_:)' could not be resolved}}
578578
@derivative(of: subscript(_:).set, wrt: self)
579-
mutating func vjpSubscriptGeneric_NoSetter<T: Differentiable>(x: T) -> (
580-
value: T, pullback: (T.TangentVector) -> TangentVector
579+
mutating func vjpSubscriptGeneric_NoSetter<U: Differentiable>(x: U) -> (
580+
value: U, pullback: (U.TangentVector) -> TangentVector
581581
) {
582582
return (x, { _ in .zero })
583583
}

test/Compatibility/accessibility.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -516,8 +516,8 @@ public struct PublicGenericIPReq<T: InternalProto> where T: PrivateProto {} // e
516516

517517
public func genericFunc<T: InternalProto>(_: T) {} // expected-error {{function cannot be declared public because its generic parameter uses an internal type}} {}
518518
public class GenericClass<T: InternalProto> { // expected-error {{generic class cannot be declared public because its generic parameter uses an internal type}}
519-
public init<T: PrivateProto>(_: T) {} // expected-error {{initializer cannot be declared public because its generic parameter uses a private type}}
520-
public func genericMethod<T: PrivateProto>(_: T) {} // expected-error {{instance method cannot be declared public because its generic parameter uses a private type}}
519+
public init<U: PrivateProto>(_: U) {} // expected-error {{initializer cannot be declared public because its generic parameter uses a private type}}
520+
public func genericMethod<U: PrivateProto>(_: U) {} // expected-error {{instance method cannot be declared public because its generic parameter uses a private type}}
521521
}
522522
public enum GenericEnum<T: InternalProto> { // expected-error {{generic enum cannot be declared public because its generic parameter uses an internal type}}
523523
case A

test/Constraints/generics.swift

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -508,11 +508,12 @@ public struct S5 {
508508

509509
// rdar://problem/24329052 - QoI: call argument archetypes not lining up leads to ambiguity errors
510510

511-
struct S_24329052<T> { // expected-note {{generic parameter 'T' of generic struct 'S_24329052' declared here}}
511+
struct S_24329052<T> { // expected-note {{generic parameter 'T' of generic struct 'S_24329052' declared here}} expected-note {{'T' previously declared here}}
512512
var foo: (T) -> Void
513513
// expected-note@+1 {{generic parameter 'T' of instance method 'bar(_:)' declared here}}
514514
func bar<T>(_ v: T) { foo(v) }
515515
// expected-error@-1 {{cannot convert value of type 'T' (generic parameter of instance method 'bar(_:)') to expected argument type 'T' (generic parameter of generic struct 'S_24329052')}}
516+
// expected-warning@-2 {{generic parameter 'T' shadows generic parameter from outer scope with the same name; this is an error in Swift 6}}
516517
}
517518

518519
extension Sequence {
@@ -943,7 +944,7 @@ do {
943944
struct Outer<T: P_eaf0300ff7a> {
944945
struct Inner<U> {}
945946

946-
func container<T>() -> Inner<T> {
947+
func container<V>() -> Inner<V> {
947948
return Inner()
948949
}
949950
}

test/Constraints/issue-53296.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ final class ViewController<T> {
2020

2121
extension ViewController: ViewDataSource where T == String {
2222
// expected-note@-1 {{requirement from conditional conformance of 'ViewController<T>' to 'ViewDataSource'}}
23-
func foo<T>() -> [T] {
23+
func foo<U>() -> [U] {
2424
return []
2525
}
2626
}

test/Constraints/members.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -553,8 +553,8 @@ func rdar_48114578() {
553553
struct S<T> {
554554
var value: T
555555

556-
static func valueOf<T>(_ v: T) -> S<T> {
557-
return S<T>(value: v)
556+
static func valueOf<U>(_ v: U) -> S<U> {
557+
return S<U>(value: v)
558558
}
559559
}
560560

test/Constraints/pack-expansion-expressions.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -219,8 +219,8 @@ do {
219219
}
220220

221221
do {
222-
func testRef<each T>() -> (repeat each T, String) { fatalError() }
223-
func testResult<each T>() -> (repeat each T) { fatalError() }
222+
func testRef<each U>() -> (repeat each U, String) { fatalError() }
223+
func testResult<each U>() -> (repeat each U) { fatalError() }
224224

225225
func experiment1<each U>() -> (repeat each U, String) {
226226
testResult() // Ok

0 commit comments

Comments
 (0)