Skip to content

Commit dd0531e

Browse files
authored
Merge pull request #65400 from slavapestov/generic-param-shadowing
Sema: Ban shadowing generic parameters from outer scopes
2 parents aae2fe2 + 290701c commit dd0531e

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

test/Constraints/super_method.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ class X<T> {
4343
}
4444

4545
class Y<U> : X<Int> {
46-
func otherMethod<U>(_ x: Int, y: U) {
46+
func otherMethod<V>(_ x: Int, y: V) {
4747
super.method(x, y: y)
4848
}
4949
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
// RUN: %target-typecheck-verify-swift
2+
3+
struct Outer<T, U> { // expected-note 2{{'T' previously declared here}}
4+
struct Inner<V> { // expected-note 2{{'V' previously declared here}}
5+
func foo<T>(_: T) {} // expected-warning {{generic parameter 'T' shadows generic parameter from outer scope with the same name; this is an error in Swift 6}}
6+
func bar<V>(_: V) {} // expected-warning {{generic parameter 'V' shadows generic parameter from outer scope with the same name; this is an error in Swift 6}}
7+
}
8+
}
9+
10+
extension Outer.Inner {
11+
func baz<T>(_: T) {} // expected-warning {{generic parameter 'T' shadows generic parameter from outer scope with the same name; this is an error in Swift 6}}
12+
func quux<V>(_: V) {} // expected-warning {{generic parameter 'V' shadows generic parameter from outer scope with the same name; this is an error in Swift 6}}
13+
}
14+
15+
extension Sequence {
16+
func bing<Self>(_: Self) {} // expected-warning {{generic parameter 'Self' shadows generic parameter from outer scope with the same name; this is an error in Swift 6}}
17+
}

test/Sema/accessibility.swift

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -935,9 +935,9 @@ package struct PackageGenericIPReq<T: InternalProto> where T: PrivateProto {} //
935935
public func genericFunc<T: InternalProto>(_: T) {} // expected-error {{function cannot be declared public because its generic parameter uses an internal type}} {}
936936
public func genericFuncPackage<T: PackageProto>(_: T) {} // expected-error {{function cannot be declared public because its generic parameter uses a package type}} {}
937937
public class GenericClass<T: InternalProto> { // expected-error {{generic class cannot be declared public because its generic parameter uses an internal type}}
938-
public init<T: PrivateProto>(_: T) {} // expected-error {{initializer cannot be declared public because its generic parameter uses a private type}}
939-
public func genericMethod<T: PrivateProto>(_: T) {} // expected-error {{instance method cannot be declared public because its generic parameter uses a private type}}
940-
public func genericMethodPackage<T: PackageProto>(_: T) {} // expected-error {{instance method cannot be declared public because its generic parameter uses a package type}}
938+
public init<U: PrivateProto>(_: U) {} // expected-error {{initializer cannot be declared public because its generic parameter uses a private type}}
939+
public func genericMethod<U: PrivateProto>(_: U) {} // expected-error {{instance method cannot be declared public because its generic parameter uses a private type}}
940+
public func genericMethodPackage<U: PackageProto>(_: U) {} // expected-error {{instance method cannot be declared public because its generic parameter uses a package type}}
941941
}
942942
public enum GenericEnum<T: InternalProto> { // expected-error {{generic enum cannot be declared public because its generic parameter uses an internal type}}
943943
case A
@@ -948,8 +948,8 @@ public enum GenericEnumPackage<T: PackageProto> { // expected-error {{generic en
948948

949949
package func packageGenericFunc<T: InternalProto>(_: T) {} // expected-error {{function cannot be declared package because its generic parameter uses an internal type}} {}
950950
package class PackageGenericClassT<T: InternalProto> { // expected-error {{generic class cannot be declared package because its generic parameter uses an internal type}}
951-
package init<T: PrivateProto>(_: T) {} // expected-error {{initializer cannot be declared package because its generic parameter uses a private type}}
952-
package func packageGenericMethod<T: PrivateProto>(_: T) {} // expected-error {{instance method cannot be declared package because its generic parameter uses a private type}}
951+
package init<U: PrivateProto>(_: U) {} // expected-error {{initializer cannot be declared package because its generic parameter uses a private type}}
952+
package func packageGenericMethod<U: PrivateProto>(_: U) {} // expected-error {{instance method cannot be declared package because its generic parameter uses a private type}}
953953
}
954954
package enum PackageGenericEnumT<T: InternalProto> { // expected-error {{generic enum cannot be declared package because its generic parameter uses an internal type}}
955955
case A

test/Sema/moveonly_illegal_types.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ enum Maybe<T> {
3939
}
4040

4141
struct CerebralValley<T> {
42-
struct GenericBro<T> {}
42+
struct GenericBro<U> {}
4343
struct TechBro {}
4444
}
4545

test/attr/attr_override.swift

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -516,7 +516,7 @@ protocol Protocol2 {}
516516
// Base class is generic, derived class is concrete.
517517

518518
class Base1<T> {
519-
func foo<T: Protocol1>(arg: T) {}
519+
func foo<U: Protocol1>(arg: U) {}
520520
}
521521
class Derived1: Base1<Protocol2> {
522522
override func foo<T>(arg: T) {} // Ok?
@@ -528,14 +528,14 @@ class Base2 {
528528
func foo() {}
529529
}
530530
class Derived2<T>: Base2 {
531-
override func foo<T>(arg: T) {} // expected-error {{method does not override any method from its superclass}}
531+
override func foo<U>(arg: U) {} // expected-error {{method does not override any method from its superclass}}
532532
}
533533

534534
// Base class generic w/ method generic, derived class generic w/ method not
535535
// generic.
536536

537537
class Base3<T> {
538-
func foo<T>(arg: T) {}
538+
func foo<U>(arg: U) {}
539539
}
540540
class Derived3<T>: Base3<T> {
541541
override func foo() {} // expected-error {{method does not override any method from its superclass}}
@@ -545,10 +545,10 @@ class Derived3<T>: Base3<T> {
545545
// but different requirement.
546546

547547
class Base4<T> {
548-
func foo<T>(arg: T) {}
548+
func foo<U>(arg: U) {}
549549
}
550550
class Derived4<T>: Base4<T> {
551-
override func foo<T: Protocol1>(arg: T) {} // expected-error {{method does not override any method from its superclass}}
551+
override func foo<U: Protocol1>(arg: U) {} // expected-error {{method does not override any method from its superclass}}
552552
}
553553

554554
// Base class not generic w/ method generic, derived class not generic w/ method
@@ -578,7 +578,7 @@ class Base7 {
578578
func foo<T: Protocol2>(arg: T) {}
579579
}
580580
class Derived7<T>: Base7 {
581-
override func foo<T: Protocol1>(arg: T) {} // expected-error {{method does not override any method from its superclass}}
581+
override func foo<U: Protocol1>(arg: U) {} // expected-error {{method does not override any method from its superclass}}
582582
}
583583

584584
// Override with orthogonal requirement on contextual generic parameter.

test/attr/attr_rethrows_protocol.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -175,7 +175,7 @@ struct ConformsToSimpleThrowsClosure<T : RethrowingProtocol> : SimpleThrowsClosu
175175
try t.source()
176176
}
177177

178-
func doIt2<T : Empty>(_: T) rethrows {}
178+
func doIt2<U : Empty>(_: U) rethrows {}
179179
// expected-note@-1 {{candidate is 'rethrows' via a conformance, but the protocol requirement is not from a '@rethrows' protocol}}
180180
}
181181

test/decl/ext/generic.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ extension X<Int, Double, String> {
2323
// expected-error@-1 {{extensions must not contain stored properties}}
2424
static let x = 0
2525
func f() -> Int {}
26-
class C<T> {}
26+
class C<W> {}
2727
}
2828

2929
typealias GGG = X<Int, Double, String>

test/decl/nested/type_in_extension.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ struct G<T> {}
44

55
extension G {
66
struct H<U> {
7-
func usesBoth<T, U>(t: T, u: U) -> (T, U) {}
7+
func usesBoth<T1, U1>(t: T1, u: U1) -> (T1, U1) {}
88
}
99
}
1010

test/decl/nested/type_in_function.swift

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -85,8 +85,8 @@ class OuterGenericClass<T> {
8585
init(t: T) { super.init(); self.t = t }
8686
}
8787

88-
class InnerGenericClass<U> : OuterGenericClass<U> // expected-error {{type 'InnerGenericClass' cannot be nested in generic function 'genericFunction'}}
89-
where U : Racoon, U.Stripes == T {
88+
class InnerGenericClass<V> : OuterGenericClass<V> // expected-error {{type 'InnerGenericClass' cannot be nested in generic function 'genericFunction'}}
89+
where V : Racoon, V.Stripes == T {
9090
let t: T
9191

9292
init(t: T) { super.init(); self.t = t }
@@ -130,7 +130,7 @@ func genericFunction<T>(t: T) {
130130
class First : Second<T>.UnknownType { }
131131
// expected-error@-1 {{type 'First' cannot be nested in generic function 'genericFunction(t:)'}}
132132
// expected-error@-2 {{'UnknownType' is not a member type of generic class 'type_in_function.Second<T>'}}
133-
class Second<T> : Second { } // expected-note{{'Second' declared here}}
133+
class Second<U> : Second { } // expected-note{{'Second' declared here}}
134134
// expected-error@-1 {{type 'Second' cannot be nested in generic function 'genericFunction(t:)'}}
135135
// expected-error@-2 {{'Second' inherits from itself}}
136136
}

test/decl/nested/type_in_type.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -106,8 +106,8 @@ class OuterGenericClass<T> {
106106
}
107107

108108
class Middle {
109-
class Inner1<T> {}
110-
class Inner2<T> : Middle where T: Inner1<Int> {}
109+
class Inner1<U> {}
110+
class Inner2<U> : Middle where U: Inner1<Int> {}
111111
}
112112
}
113113

test/decl/overload.swift

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -204,9 +204,9 @@ struct X5<t, u, v> {
204204
static func u() {}
205205
typealias v = String
206206

207-
func foo<t>(_ t: t) {
208-
let t = t
209-
_ = t
207+
func foo<w>(_ w: w) {
208+
let w = w
209+
_ = w
210210
}
211211
}
212212

0 commit comments

Comments
 (0)