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:
Joe Groff
2013-01-24 02:29:41 +00:00
parent 4789ba71fb
commit 057f1b6468
7 changed files with 171 additions and 8 deletions

View File

@@ -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:

View File

@@ -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", ())

View File

@@ -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();

View File

@@ -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);

View File

@@ -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.

View File

@@ -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);

View 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}}
}
*/
}