Skip to content

Commit 9017bf7

Browse files
committed
Sema: Improve error messages for super in illegal context
1 parent 28de53f commit 9017bf7

File tree

7 files changed

+137
-34
lines changed

7 files changed

+137
-34
lines changed

include/swift/AST/DiagnosticsSema.def

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4315,10 +4315,16 @@ ERROR(no_MaxBuiltinFloatType_found,none,
43154315
ERROR(no_member_of_module,none,
43164316
"module %0 has no member named %1", (Identifier, DeclNameRef))
43174317

4318-
ERROR(super_with_no_base_class,none,
4319-
"'super' members cannot be referenced in a root class", ())
4320-
ERROR(super_not_in_class_method,none,
4321-
"'super' cannot be used outside of class members", ())
4318+
ERROR(super_no_superclass,none,
4319+
"'super' cannot be used in %select{|extension of }0class %1 because it "
4320+
"has no superclass",
4321+
(bool, const ClassDecl *))
4322+
ERROR(super_invalid_context,none,
4323+
"'super' cannot be used outside of a class computed property, method, "
4324+
"initializer, deinitializer, or subscript", ())
4325+
ERROR(super_in_nonclass_type,none,
4326+
"'super' cannot be used in non-class type %0",
4327+
(const NominalTypeDecl *))
43224328

43234329
ERROR(unqualified_init,none,
43244330
"initializer expression requires explicit access"

lib/Sema/CSGen.cpp

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1608,8 +1608,8 @@ namespace {
16081608

16091609
// Resolve the super type of 'self'.
16101610
return getSuperType(E->getSelf(), E->getLoc(),
1611-
diag::super_not_in_class_method,
1612-
diag::super_with_no_base_class);
1611+
diag::super_invalid_context,
1612+
diag::super_no_superclass);
16131613
}
16141614

16151615
Type
@@ -3298,10 +3298,9 @@ namespace {
32983298
return resultType;
32993299
}
33003300

3301-
Type getSuperType(VarDecl *selfDecl,
3302-
SourceLoc diagLoc,
3301+
Type getSuperType(VarDecl *selfDecl, SourceLoc diagLoc,
33033302
Diag<> diag_not_in_class,
3304-
Diag<> diag_no_base_class) {
3303+
Diag<bool, const ClassDecl *> diag_no_superclass) {
33053304
DeclContext *typeContext = selfDecl->getDeclContext()->getParent();
33063305
assert(typeContext && "constructor without parent context?!");
33073306

@@ -3312,7 +3311,10 @@ namespace {
33123311
return Type();
33133312
}
33143313
if (!classDecl->hasSuperclass()) {
3315-
de.diagnose(diagLoc, diag_no_base_class);
3314+
de.diagnose(
3315+
diagLoc, diag_no_superclass,
3316+
/*isExtension*/ isa<ExtensionDecl>(typeContext->getAsDecl()),
3317+
classDecl);
33163318
return Type();
33173319
}
33183320

lib/Sema/PreCheckExpr.cpp

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1810,8 +1810,20 @@ void PreCheckExpression::markAcceptableDiscardExprs(Expr *E) {
18101810

18111811
VarDecl *PreCheckExpression::getImplicitSelfDeclForSuperContext(SourceLoc Loc) {
18121812
auto *methodContext = DC->getInnermostMethodContext();
1813-
if (!methodContext) {
1814-
Ctx.Diags.diagnose(Loc, diag::super_not_in_class_method);
1813+
1814+
if (auto *typeContext = DC->getInnermostTypeContext()) {
1815+
auto *nominal = typeContext->getSelfNominalTypeDecl();
1816+
auto *classDecl = dyn_cast<ClassDecl>(nominal);
1817+
1818+
if (!classDecl) {
1819+
Ctx.Diags.diagnose(Loc, diag::super_in_nonclass_type, nominal);
1820+
return nullptr;
1821+
} else if (!methodContext) {
1822+
Ctx.Diags.diagnose(Loc, diag::super_invalid_context);
1823+
return nullptr;
1824+
}
1825+
} else {
1826+
Ctx.Diags.diagnose(Loc, diag::super_invalid_context);
18151827
return nullptr;
18161828
}
18171829

test/Constraints/super_constructor.swift

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,5 @@
11
// RUN: %target-typecheck-verify-swift -parse-as-library
22

3-
struct S {
4-
init() {
5-
super.init() // expected-error{{'super' cannot be used outside of class members}}
6-
}
7-
}
8-
93
class D : B {
104
func foo() {
115
super.init() // expected-error{{'super.init' cannot be called outside of an initializer}}
@@ -46,10 +40,6 @@ class B {
4640
}
4741
init(b:UnicodeScalar) { // expected-note {{candidate expects value of type 'UnicodeScalar' (aka 'Unicode.Scalar') for parameter #1}}
4842
}
49-
50-
init(z:Float) { // expected-note{{candidate expects value of type 'Float' for parameter #1}}
51-
super.init() // expected-error{{'super' members cannot be referenced in a root class}}
52-
}
5343
}
5444

5545
/// https://github.com/apple/swift/issues/45089

test/Constraints/super_method.swift

Lines changed: 1 addition & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,5 @@
11
// RUN: %target-typecheck-verify-swift -parse-as-library
22

3-
struct S {
4-
func foo() {
5-
super.foo() // expected-error{{'super' cannot be used outside of class members}}
6-
}
7-
}
8-
93
class D : B {
104
func b_foo() -> Int { return super.foo }
115

@@ -33,9 +27,6 @@ class B {
3327
func zung() -> String {}
3428

3529
var zippity : Int { return 123 }
36-
37-
func zoo() { super.zoo() } // expected-error{{'super' members cannot be referenced in a root class}}
38-
3930
}
4031

4132
class X<T> {
@@ -57,7 +48,7 @@ func use_d(_ d: D) -> Int {
5748
}
5849

5950
func not_method() {
60-
super.foo() // expected-error{{'super' cannot be used outside of class members}}
51+
super.foo() // expected-error{{'super' cannot be used outside of a class computed property, method, initializer, deinitializer, or subscript}}
6152
}
6253

6354
// rdar://problem/50819554 - inability to properly resolve superclass shouldn't crash the solver

test/Parse/invalid.swift

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,6 @@ func foo() {
2727
// expected-error @-1 {{cannot find 'skview' in scope}}
2828
}
2929

30-
super.init() // expected-error {{'super' cannot be used outside of class members}}
31-
3230
switch state { // expected-error {{cannot find 'state' in scope}}
3331
let duration : Int = 0 // expected-error {{all statements inside a switch must be covered by a 'case' or 'default'}}
3432
case 1:
Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
// RUN: %target-typecheck-verify-swift
2+
3+
class Root {
4+
let x = 0
5+
6+
// expected-error@+1 {{'super' cannot be used outside of a class computed property, method, initializer, deinitializer, or subscript}}
7+
let testStoredRoot = super.x
8+
9+
var testComputedRoot: Int {
10+
// expected-error@+1 {{'super' cannot be used in class 'Root' because it has no superclass}}
11+
let _ = super.x
12+
}
13+
14+
init(root: Void) {
15+
// expected-error@+1 {{'super' cannot be used in class 'Root' because it has no superclass}}
16+
super.x
17+
// expected-error@+1 {{'super' cannot be used in class 'Root' because it has no superclass}}
18+
super.init()
19+
}
20+
21+
func testMethodRoot(
22+
// expected-error@+1 {{'super' cannot be used in class 'Root' because it has no superclass}}
23+
_: Int = super.x
24+
) {
25+
// expected-error@+1 {{'super' cannot be used in class 'Root' because it has no superclass}}
26+
super.testMethodRoot()
27+
}
28+
29+
deinit {
30+
// expected-error@+1 {{'super' cannot be used in class 'Root' because it has no superclass}}
31+
super.x
32+
}
33+
}
34+
35+
extension Root {
36+
func testMethodRootExtension() {
37+
// expected-error@+1 {{'super' cannot be used in extension of class 'Root' because it has no superclass}}
38+
super.x
39+
}
40+
}
41+
42+
class Derived: Root {
43+
// expected-error@+1 {{'super' cannot be used outside of a class computed property, method, initializer, deinitializer, or subscript}}
44+
let testStoredDerived = super.x
45+
46+
var testComputedDerived: Int {
47+
super.x
48+
}
49+
50+
init(derived: Void) {
51+
let _ = super.x
52+
}
53+
54+
func testMethodDerived(_: Int = super.x) -> Int {
55+
super.x
56+
}
57+
58+
deinit {
59+
let _ = super.x
60+
}
61+
}
62+
63+
protocol P: Derived {}
64+
extension P {
65+
func test() {
66+
// expected-error@+1 {{'super' cannot be used in non-class type 'P'}}
67+
super.x
68+
}
69+
}
70+
71+
enum E {
72+
case a(
73+
// expected-error@+1 {{'super' cannot be used in non-class type 'E'}}
74+
_: Int = super.undef
75+
)
76+
77+
func test() {
78+
// expected-error@+1 {{'super' cannot be used in non-class type 'E'}}
79+
super.undef
80+
}
81+
}
82+
83+
struct S {
84+
// expected-error@+1 {{'super' cannot be used in non-class type 'S'}}
85+
let testStoredRoot = super.undef
86+
87+
init() {
88+
// expected-error@+1 {{'super' cannot be used in non-class type 'S'}}
89+
super.init()
90+
}
91+
92+
func test() {
93+
// expected-error@+1 {{'super' cannot be used in non-class type 'S'}}
94+
super.undef
95+
}
96+
}
97+
98+
func test() {
99+
// expected-error@+1 {{'super' cannot be used outside of a class computed property, method, initializer, deinitializer, or subscript}}
100+
super.undef
101+
}
102+
103+
// expected-error@+1 {{'super' cannot be used outside of a class computed property, method, initializer, deinitializer, or subscript}}
104+
super.init()

0 commit comments

Comments
 (0)