mirror of
https://github.com/apple/swift.git
synced 2025-12-21 12:14:44 +01:00
Sema: Type check non-overloaded super.constructor.
Implement base class constructor lookup to resolve the function reference for SuperConstructorRefCallExprs. Swift SVN r3855
This commit is contained in:
@@ -1369,6 +1369,9 @@ class ConstructorDecl : public ValueDecl, public DeclContext {
|
||||
BraceStmt *Body;
|
||||
VarDecl *ImplicitThisDecl;
|
||||
GenericParamList *GenericParams;
|
||||
|
||||
/// The type of the initializing constructor.
|
||||
Type InitializerType = Type();
|
||||
|
||||
/// \brief When non-null, the expression that should be used to
|
||||
/// allocate 'this'.
|
||||
@@ -1429,6 +1432,10 @@ public:
|
||||
static bool classof(const DeclContext *DC) {
|
||||
return DC->getContextKind() == DeclContextKind::ConstructorDecl;
|
||||
}
|
||||
|
||||
/// Get the type of the initializing constructor.
|
||||
Type getInitializerType() const { return InitializerType; }
|
||||
void setInitializerType(Type t) { InitializerType = t; }
|
||||
};
|
||||
|
||||
/// DestructorDecl - Declares a destructor for a type. For example:
|
||||
|
||||
@@ -452,6 +452,8 @@ ERROR(expected_identifier_after_super_dot_expr,expr_parsing,none,
|
||||
"expected identifier or 'constructor' after super '.' expression", ())
|
||||
ERROR(expected_dot_or_subscript_after_super,expr_parsing,none,
|
||||
"expected '.' or '[' after 'super'", ())
|
||||
ERROR(super_constructor_not_in_constructor,expr_parsing,none,
|
||||
"'super.constructor' cannot be called outside of a constructor", ())
|
||||
|
||||
ERROR(expected_expr_closure,expr_parsing,none,
|
||||
"expected expression in closure", ())
|
||||
@@ -884,6 +886,11 @@ ERROR(existential_member_assoc_types,sema_tca,none,
|
||||
ERROR(closure_not_function_type,sema_tce,none,
|
||||
"closure inferred to have non-function type %0", (Type))
|
||||
|
||||
ERROR(super_constructor_not_in_class_constructor,sema_tce,none,
|
||||
"'super.constructor' can only be called in a class constructor", ())
|
||||
ERROR(super_constructor_with_no_base_class,sema_tce,none,
|
||||
"'super.constructor' cannot be called in a root class constructor", ())
|
||||
|
||||
// Operators
|
||||
ERROR(binop_not_infix,sema_tce,none,
|
||||
"binary operator has no infix attribute", ())
|
||||
|
||||
@@ -212,7 +212,7 @@ NullablePtr<Expr> Parser::parseExprNew() {
|
||||
/// 'super' '[' expr ']'
|
||||
NullablePtr<Expr> Parser::parseExprSuper() {
|
||||
SourceLoc superLoc = consumeToken(tok::kw_super);
|
||||
|
||||
|
||||
if (Tok.is(tok::period)) {
|
||||
// 'super.' must be a member or constructor ref.
|
||||
SourceLoc dotLoc = consumeToken(tok::period);
|
||||
@@ -220,11 +220,22 @@ NullablePtr<Expr> Parser::parseExprSuper() {
|
||||
if (Tok.is(tok::kw_constructor)) {
|
||||
// super.constructor
|
||||
SourceLoc ctorLoc = consumeToken(tok::kw_constructor);
|
||||
|
||||
// The function expr will be resolved by sema. The base however should be
|
||||
// 'this', which we get from the constructor context.
|
||||
Expr *thisExpr = nullptr;
|
||||
ConstructorDecl *ctor = dyn_cast<ConstructorDecl>(CurDeclContext);
|
||||
if (ctor) {
|
||||
thisExpr = new (Context) DeclRefExpr(ctor->getImplicitThisDecl(),
|
||||
SourceLoc());
|
||||
} else
|
||||
diagnose(ctorLoc, diag::super_constructor_not_in_constructor);
|
||||
|
||||
return new (Context) SuperConstructorRefCallExpr(superLoc,
|
||||
dotLoc,
|
||||
ctorLoc,
|
||||
nullptr,
|
||||
nullptr);
|
||||
/*fnExpr=*/ nullptr,
|
||||
/*baseExpr=*/ thisExpr);
|
||||
} else {
|
||||
// super.foo
|
||||
SourceLoc nameLoc = Tok.getLoc();
|
||||
|
||||
@@ -574,6 +574,8 @@ public:
|
||||
CD->setType(ErrorType::get(TC.Context));
|
||||
} else {
|
||||
Type FnTy;
|
||||
Type AllocFnTy;
|
||||
Type InitFnTy;
|
||||
if (GenericParamList *innerGenericParams = CD->getGenericParams()) {
|
||||
innerGenericParams->setOuterParameters(outerGenericParams);
|
||||
FnTy = PolymorphicFunctionType::get(CD->getArguments()->getType(),
|
||||
@@ -584,12 +586,16 @@ public:
|
||||
ThisTy, TC.Context);
|
||||
Type ThisMetaTy = MetaTypeType::get(ThisTy, TC.Context);
|
||||
if (outerGenericParams) {
|
||||
FnTy = PolymorphicFunctionType::get(ThisMetaTy, FnTy,
|
||||
outerGenericParams, TC.Context);
|
||||
AllocFnTy = PolymorphicFunctionType::get(ThisMetaTy, FnTy,
|
||||
outerGenericParams, TC.Context);
|
||||
InitFnTy = PolymorphicFunctionType::get(ThisTy, FnTy,
|
||||
outerGenericParams, TC.Context);
|
||||
} else {
|
||||
FnTy = FunctionType::get(ThisMetaTy, FnTy, TC.Context);
|
||||
AllocFnTy = FunctionType::get(ThisMetaTy, FnTy, TC.Context);
|
||||
InitFnTy = FunctionType::get(ThisTy, FnTy, TC.Context);
|
||||
}
|
||||
CD->setType(FnTy);
|
||||
CD->setType(AllocFnTy);
|
||||
CD->setInitializerType(InitFnTy);
|
||||
}
|
||||
|
||||
validateAttributes(CD);
|
||||
|
||||
@@ -834,6 +834,10 @@ public:
|
||||
llvm_unreachable("super member ref not implemented");
|
||||
}
|
||||
|
||||
Expr *visitSuperConstructorRefCallExpr(SuperConstructorRefCallExpr *E) {
|
||||
return TC.semaSuperConstructorRefCallExpr(E);
|
||||
}
|
||||
|
||||
Expr *visitExistentialMemberRefExpr(ExistentialMemberRefExpr *E) {
|
||||
if (E->getDecl()->getType()->is<ErrorType>())
|
||||
return nullptr;
|
||||
@@ -1350,6 +1354,64 @@ static Type makeSimilarLValue(Type objectType, Type lvalueType,
|
||||
return LValueType::get(objectType, qs, Context);
|
||||
}
|
||||
|
||||
Expr *TypeChecker::semaSuperConstructorRefCallExpr(
|
||||
SuperConstructorRefCallExpr *e) {
|
||||
// If we already diagnosed an error, don't complain again.
|
||||
if (e->getType() && e->getType()->is<ErrorType>())
|
||||
return nullptr;
|
||||
|
||||
// If we already resolved the constructor function, analyze as a typical
|
||||
// ApplyExpr.
|
||||
if (e->getFn()) {
|
||||
return semaApplyExpr(e);
|
||||
}
|
||||
|
||||
// If this is a valid super constructor call, the base should be a reference
|
||||
// to a 'this' decl.
|
||||
Expr *base = e->getArg();
|
||||
if (!base || base->getType()->is<ErrorType>())
|
||||
return nullptr;
|
||||
ValueDecl *thisDecl = cast<DeclRefExpr>(base)->getDecl();
|
||||
|
||||
// Get the superclass context, which will be the parent of the constructor
|
||||
// context.
|
||||
DeclContext *typeContext = thisDecl->getDeclContext()->getParent();
|
||||
assert(typeContext && "constructor without parent context?!");
|
||||
ClassDecl *classDecl = dyn_cast<ClassDecl>(typeContext);
|
||||
if (!classDecl) {
|
||||
diagnose(e->getLoc(), diag::super_constructor_not_in_class_constructor);
|
||||
e->setType(ErrorType::get(Context));
|
||||
return e;
|
||||
}
|
||||
// The class must have a base class.
|
||||
if (!classDecl->hasBaseClass()) {
|
||||
diagnose(e->getLoc(), diag::super_constructor_with_no_base_class);
|
||||
e->setType(ErrorType::get(Context));
|
||||
return e;
|
||||
}
|
||||
|
||||
Type superTy = classDecl->getBaseClass();
|
||||
|
||||
// Look for constructors in the superclass.
|
||||
ConstructorLookup lookup(superTy, TU);
|
||||
assert(lookup.isSuccess() && "class with no constructor?!");
|
||||
|
||||
// If there's only one, use it.
|
||||
if (lookup.Results.size() == 1) {
|
||||
ConstructorDecl *theCtor = cast<ConstructorDecl>(lookup.Results[0]);
|
||||
assert(theCtor->getInitializerType() && "ctor not type checked");
|
||||
// Since we're inside a constructor and have already allocated the instance,
|
||||
// we reference the superclass initializing constructor, not the normal
|
||||
// allocating constructor.
|
||||
e->setFn(new (Context) DeclRefExpr(theCtor, e->getLoc(),
|
||||
theCtor->getInitializerType()));
|
||||
// Type-check the call.
|
||||
return semaApplyExpr(e);
|
||||
} else {
|
||||
// Otherwise, build an overloaded reference.
|
||||
llvm_unreachable("todo: overloaded super ctors");
|
||||
}
|
||||
}
|
||||
|
||||
Expr *TypeChecker::semaUnresolvedDotExpr(UnresolvedDotExpr *E) {
|
||||
// If we already diagnosed this as an error, don't complain again.
|
||||
@@ -1366,7 +1428,7 @@ Expr *TypeChecker::semaUnresolvedDotExpr(UnresolvedDotExpr *E) {
|
||||
}
|
||||
|
||||
if (BaseTy->is<ErrorType>())
|
||||
return 0; // Squelch an erroneous subexpression.
|
||||
return nullptr; // Squelch an erroneous subexpression.
|
||||
|
||||
// If the base expression is not an lvalue, make everything inside it
|
||||
// materializable.
|
||||
|
||||
@@ -364,6 +364,8 @@ public:
|
||||
Expr *semaSubscriptExpr(GenericSubscriptExpr *SE);
|
||||
Expr *semaApplyExpr(ApplyExpr *E);
|
||||
Expr *semaUnresolvedDotExpr(UnresolvedDotExpr *E);
|
||||
Expr *semaSuperConstructorRefCallExpr(SuperConstructorRefCallExpr *E);
|
||||
|
||||
void typeCheckIgnoredExpr(Expr *E);
|
||||
void typeCheckFunctionBody(FuncExpr *FE);
|
||||
void typeCheckConstructorBody(ConstructorDecl *CD);
|
||||
|
||||
68
test/TypeCoercion/super_constructors.swift
Normal file
68
test/TypeCoercion/super_constructors.swift
Normal file
@@ -0,0 +1,68 @@
|
||||
// RUN: %swift %s -parse-as-library -verify
|
||||
|
||||
struct S {
|
||||
constructor() {
|
||||
super.constructor() // expected-error{{'super.constructor' can only be called in a class constructor}}
|
||||
}
|
||||
}
|
||||
|
||||
class D : B {
|
||||
func foo() {
|
||||
super.constructor() // expected-error{{'super.constructor' cannot be called outside of a constructor}}
|
||||
}
|
||||
|
||||
constructor(a:Int) {
|
||||
super.constructor()
|
||||
}
|
||||
|
||||
/*
|
||||
constructor(b:Int) {
|
||||
super.constructor()
|
||||
super.constructor() // e/xpected-error{{'super.constructor' can only be called once per constructor}}
|
||||
}
|
||||
|
||||
constructor(c:Int) {
|
||||
super.constructor()
|
||||
super.constructor(0) // e/xpected-error{{'super.constructor' can only be called once per constructor}}
|
||||
}
|
||||
|
||||
constructor(d:Int) {
|
||||
(super.constructor(),
|
||||
super.constructor()) // e/xpected-error{{'super.constructor' can only be called once per constructor}}
|
||||
}
|
||||
|
||||
constructor(e:Int) {
|
||||
super.constructor('x') // e/xpected-error{{xxx ambiguous}}
|
||||
}
|
||||
|
||||
constructor(f:Int) {
|
||||
super.constructor(a='x')
|
||||
}
|
||||
|
||||
constructor(g:Int) {
|
||||
super.constructor("aoeu") // e/xpected-error{{xxx no matching call}}
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
class B {
|
||||
var foo : (bar:Int)
|
||||
func bar() {}
|
||||
|
||||
constructor() {
|
||||
}
|
||||
/*
|
||||
constructor(x:Int) {
|
||||
}
|
||||
|
||||
constructor(a:Char) {
|
||||
}
|
||||
constructor(b:Char) {
|
||||
}
|
||||
|
||||
constructor(z:Float) {
|
||||
super.constructor() // e/xpected-error{{'super.constructor' cannot be called in a root class constructor}}
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user