Sema: Improve error messages for super in illegal context

This commit is contained in:
Anthony Latsis
2023-12-27 01:05:38 +03:00
parent 28de53f913
commit 9017bf77b1
7 changed files with 137 additions and 34 deletions

View File

@@ -4315,10 +4315,16 @@ ERROR(no_MaxBuiltinFloatType_found,none,
ERROR(no_member_of_module,none,
"module %0 has no member named %1", (Identifier, DeclNameRef))
ERROR(super_with_no_base_class,none,
"'super' members cannot be referenced in a root class", ())
ERROR(super_not_in_class_method,none,
"'super' cannot be used outside of class members", ())
ERROR(super_no_superclass,none,
"'super' cannot be used in %select{|extension of }0class %1 because it "
"has no superclass",
(bool, const ClassDecl *))
ERROR(super_invalid_context,none,
"'super' cannot be used outside of a class computed property, method, "
"initializer, deinitializer, or subscript", ())
ERROR(super_in_nonclass_type,none,
"'super' cannot be used in non-class type %0",
(const NominalTypeDecl *))
ERROR(unqualified_init,none,
"initializer expression requires explicit access"

View File

@@ -1608,8 +1608,8 @@ namespace {
// Resolve the super type of 'self'.
return getSuperType(E->getSelf(), E->getLoc(),
diag::super_not_in_class_method,
diag::super_with_no_base_class);
diag::super_invalid_context,
diag::super_no_superclass);
}
Type
@@ -3298,10 +3298,9 @@ namespace {
return resultType;
}
Type getSuperType(VarDecl *selfDecl,
SourceLoc diagLoc,
Type getSuperType(VarDecl *selfDecl, SourceLoc diagLoc,
Diag<> diag_not_in_class,
Diag<> diag_no_base_class) {
Diag<bool, const ClassDecl *> diag_no_superclass) {
DeclContext *typeContext = selfDecl->getDeclContext()->getParent();
assert(typeContext && "constructor without parent context?!");
@@ -3312,7 +3311,10 @@ namespace {
return Type();
}
if (!classDecl->hasSuperclass()) {
de.diagnose(diagLoc, diag_no_base_class);
de.diagnose(
diagLoc, diag_no_superclass,
/*isExtension*/ isa<ExtensionDecl>(typeContext->getAsDecl()),
classDecl);
return Type();
}

View File

@@ -1810,8 +1810,20 @@ void PreCheckExpression::markAcceptableDiscardExprs(Expr *E) {
VarDecl *PreCheckExpression::getImplicitSelfDeclForSuperContext(SourceLoc Loc) {
auto *methodContext = DC->getInnermostMethodContext();
if (!methodContext) {
Ctx.Diags.diagnose(Loc, diag::super_not_in_class_method);
if (auto *typeContext = DC->getInnermostTypeContext()) {
auto *nominal = typeContext->getSelfNominalTypeDecl();
auto *classDecl = dyn_cast<ClassDecl>(nominal);
if (!classDecl) {
Ctx.Diags.diagnose(Loc, diag::super_in_nonclass_type, nominal);
return nullptr;
} else if (!methodContext) {
Ctx.Diags.diagnose(Loc, diag::super_invalid_context);
return nullptr;
}
} else {
Ctx.Diags.diagnose(Loc, diag::super_invalid_context);
return nullptr;
}

View File

@@ -1,11 +1,5 @@
// RUN: %target-typecheck-verify-swift -parse-as-library
struct S {
init() {
super.init() // expected-error{{'super' cannot be used outside of class members}}
}
}
class D : B {
func foo() {
super.init() // expected-error{{'super.init' cannot be called outside of an initializer}}
@@ -46,10 +40,6 @@ class B {
}
init(b:UnicodeScalar) { // expected-note {{candidate expects value of type 'UnicodeScalar' (aka 'Unicode.Scalar') for parameter #1}}
}
init(z:Float) { // expected-note{{candidate expects value of type 'Float' for parameter #1}}
super.init() // expected-error{{'super' members cannot be referenced in a root class}}
}
}
/// https://github.com/apple/swift/issues/45089

View File

@@ -1,11 +1,5 @@
// RUN: %target-typecheck-verify-swift -parse-as-library
struct S {
func foo() {
super.foo() // expected-error{{'super' cannot be used outside of class members}}
}
}
class D : B {
func b_foo() -> Int { return super.foo }
@@ -33,9 +27,6 @@ class B {
func zung() -> String {}
var zippity : Int { return 123 }
func zoo() { super.zoo() } // expected-error{{'super' members cannot be referenced in a root class}}
}
class X<T> {
@@ -57,7 +48,7 @@ func use_d(_ d: D) -> Int {
}
func not_method() {
super.foo() // expected-error{{'super' cannot be used outside of class members}}
super.foo() // expected-error{{'super' cannot be used outside of a class computed property, method, initializer, deinitializer, or subscript}}
}
// rdar://problem/50819554 - inability to properly resolve superclass shouldn't crash the solver

View File

@@ -27,8 +27,6 @@ func foo() {
// expected-error @-1 {{cannot find 'skview' in scope}}
}
super.init() // expected-error {{'super' cannot be used outside of class members}}
switch state { // expected-error {{cannot find 'state' in scope}}
let duration : Int = 0 // expected-error {{all statements inside a switch must be covered by a 'case' or 'default'}}
case 1:

View File

@@ -0,0 +1,104 @@
// RUN: %target-typecheck-verify-swift
class Root {
let x = 0
// expected-error@+1 {{'super' cannot be used outside of a class computed property, method, initializer, deinitializer, or subscript}}
let testStoredRoot = super.x
var testComputedRoot: Int {
// expected-error@+1 {{'super' cannot be used in class 'Root' because it has no superclass}}
let _ = super.x
}
init(root: Void) {
// expected-error@+1 {{'super' cannot be used in class 'Root' because it has no superclass}}
super.x
// expected-error@+1 {{'super' cannot be used in class 'Root' because it has no superclass}}
super.init()
}
func testMethodRoot(
// expected-error@+1 {{'super' cannot be used in class 'Root' because it has no superclass}}
_: Int = super.x
) {
// expected-error@+1 {{'super' cannot be used in class 'Root' because it has no superclass}}
super.testMethodRoot()
}
deinit {
// expected-error@+1 {{'super' cannot be used in class 'Root' because it has no superclass}}
super.x
}
}
extension Root {
func testMethodRootExtension() {
// expected-error@+1 {{'super' cannot be used in extension of class 'Root' because it has no superclass}}
super.x
}
}
class Derived: Root {
// expected-error@+1 {{'super' cannot be used outside of a class computed property, method, initializer, deinitializer, or subscript}}
let testStoredDerived = super.x
var testComputedDerived: Int {
super.x
}
init(derived: Void) {
let _ = super.x
}
func testMethodDerived(_: Int = super.x) -> Int {
super.x
}
deinit {
let _ = super.x
}
}
protocol P: Derived {}
extension P {
func test() {
// expected-error@+1 {{'super' cannot be used in non-class type 'P'}}
super.x
}
}
enum E {
case a(
// expected-error@+1 {{'super' cannot be used in non-class type 'E'}}
_: Int = super.undef
)
func test() {
// expected-error@+1 {{'super' cannot be used in non-class type 'E'}}
super.undef
}
}
struct S {
// expected-error@+1 {{'super' cannot be used in non-class type 'S'}}
let testStoredRoot = super.undef
init() {
// expected-error@+1 {{'super' cannot be used in non-class type 'S'}}
super.init()
}
func test() {
// expected-error@+1 {{'super' cannot be used in non-class type 'S'}}
super.undef
}
}
func test() {
// expected-error@+1 {{'super' cannot be used outside of a class computed property, method, initializer, deinitializer, or subscript}}
super.undef
}
// expected-error@+1 {{'super' cannot be used outside of a class computed property, method, initializer, deinitializer, or subscript}}
super.init()