Permalink
Browse files

[SE-0021] Allow naming of specific initializers via "self.init(foo:ba…

…r:)".
  • Loading branch information...
DougGregor committed Jan 12, 2016
1 parent 5f07f6b commit c9c1d1390c621dc3932c0a77c8a191e6411b71f2
View
@@ -1051,11 +1051,15 @@ class UnresolvedConstructorExpr : public Expr {
Expr *SubExpr;
SourceLoc DotLoc;
SourceLoc ConstructorLoc;
+ DeclName Name;
+
public:
UnresolvedConstructorExpr(Expr *SubExpr, SourceLoc DotLoc,
- SourceLoc ConstructorLoc, bool Implicit)
+ SourceLoc ConstructorLoc, DeclName Name,
+ bool Implicit)
: Expr(ExprKind::UnresolvedConstructor, Implicit),
- SubExpr(SubExpr), DotLoc(DotLoc), ConstructorLoc(ConstructorLoc)
+ SubExpr(SubExpr), DotLoc(DotLoc), ConstructorLoc(ConstructorLoc),
+ Name(Name)
{}
Expr *getSubExpr() const { return SubExpr; }
@@ -1065,6 +1069,8 @@ class UnresolvedConstructorExpr : public Expr {
SourceLoc getConstructorLoc() const { return ConstructorLoc; }
SourceLoc getDotLoc() const { return DotLoc; }
+ DeclName getName() const { return Name; }
+
SourceLoc getStartLoc() const { return SubExpr->getStartLoc(); }
SourceLoc getEndLoc() const { return ConstructorLoc; }
View
@@ -1650,7 +1650,8 @@ class PrintExpr : public ExprVisitor<PrintExpr> {
OS << ')';
}
void visitUnresolvedConstructorExpr(UnresolvedConstructorExpr *E) {
- printCommon(E, "unresolved_constructor") << '\n';
+ printCommon(E, "unresolved_constructor")
+ << " name=" << E->getName() << '\n';
printRec(E->getSubExpr());
OS << ')';
}
View
@@ -577,44 +577,38 @@ ParserResult<Expr> Parser::parseExprSuper() {
SourceLoc dotLoc = consumeToken(tok::period);
- // FIXME: This code is copy-paste from the general handling for kw_init.
- if (Tok.is(tok::kw_init)) {
-
- if (ErrorOccurred)
- return makeParserError();
-
- // super.init
- SourceLoc ctorLoc = consumeToken();
-
- // The constructor decl will be resolved by sema.
- // FIXME: Extend representation with DeclName!
- Expr *result = new (Context) UnresolvedConstructorExpr(superRef,
- dotLoc, ctorLoc,
- /*Implicit=*/false);
- return makeParserResult(result);
- } else if (Tok.is(tok::code_complete)) {
+ if (Tok.is(tok::code_complete)) {
if (CodeCompletion) {
if (auto *SRE = dyn_cast<SuperRefExpr>(superRef))
CodeCompletion->completeExprSuperDot(SRE);
}
+
// Eat the code completion token because we handled it.
consumeToken(tok::code_complete);
return makeParserCodeCompletionResult(superRef);
- } else {
- // super.foo
- SourceLoc nameLoc;
- DeclName name = parseUnqualifiedIdentifier(
- /*allowInit=*/false,
- nameLoc,
- diag::expected_identifier_after_super_dot_expr);
- if (!name)
- return nullptr;
+ }
- return makeParserResult(new (Context) UnresolvedDotExpr(superRef, dotLoc,
- name, nameLoc,
- /*Implicit=*/false));
+ SourceLoc nameLoc;
+ DeclName name = parseUnqualifiedIdentifier(
+ /*allowInit=*/true,
+ nameLoc,
+ diag::expected_identifier_after_super_dot_expr);
+ if (!name)
+ return nullptr;
+
+ if (name.getBaseName() == Context.Id_init) {
+ Expr *result = new (Context) UnresolvedConstructorExpr(superRef,
+ dotLoc, nameLoc, name,
+ /*Implicit=*/false);
+ return makeParserResult(result);
}
- } else if (Tok.isFollowingLSquare()) {
+
+ return makeParserResult(
+ new (Context) UnresolvedDotExpr(superRef, dotLoc, name, nameLoc,
+ /*Implicit=*/false));
+ }
+
+ if (Tok.isFollowingLSquare()) {
// super[expr]
ParserResult<Expr> idx = parseExprList(tok::l_square, tok::r_square);
if (idx.hasCodeCompletion())
@@ -623,6 +617,7 @@ ParserResult<Expr> Parser::parseExprSuper() {
return nullptr;
return makeParserResult(new (Context) SubscriptExpr(superRef, idx.get()));
}
+
if (Tok.is(tok::code_complete)) {
if (CodeCompletion) {
if (auto *SRE = dyn_cast<SuperRefExpr>(superRef))
@@ -1033,7 +1028,8 @@ ParserResult<Expr> Parser::parseExprPostfix(Diag<> ID, bool isExprBasic) {
SourceLoc TokLoc = Tok.getLoc();
if (consumeIf(tok::period) || consumeIf(tok::period_prefix)) {
// Non-identifier cases.
- if (Tok.isNot(tok::identifier) && Tok.isNot(tok::integer_literal)) {
+ if (Tok.isNot(tok::identifier) && Tok.isNot(tok::integer_literal) &&
+ Tok.isNot(tok::kw_init)) {
// A metatype expr.
if (Tok.is(tok::kw_dynamicType)) {
Result = makeParserResult(
@@ -1060,20 +1056,6 @@ ParserResult<Expr> Parser::parseExprPostfix(Diag<> ID, bool isExprBasic) {
consumeToken();
}
- // expr-init ::= expr-postfix '.' 'init'.
- if (Tok.is(tok::kw_init)) {
- // Form the reference to the constructor.
- // FIXME: Handle a full DeclName.
- Expr *initRef = new (Context) UnresolvedConstructorExpr(
- Result.get(),
- TokLoc,
- Tok.getLoc(),
- /*Implicit=*/false);
- consumeToken(tok::kw_init);
- Result = makeParserResult(initRef);
- continue;
- }
-
if (Tok.is(tok::code_complete)) {
if (CodeCompletion && Result.isNonNull())
CodeCompletion->completeDotExpr(Result.get(), /*DotLoc=*/TokLoc);
@@ -1101,18 +1083,26 @@ ParserResult<Expr> Parser::parseExprPostfix(Diag<> ID, bool isExprBasic) {
if (Result.isParseError())
continue;
-
- if (Tok.is(tok::identifier)) {
+ if (Tok.isAny(tok::identifier, tok::kw_init)) {
SourceLoc NameLoc;
- DeclName Name;
- Name = parseUnqualifiedIdentifier(/*allowInit=*/false,
- NameLoc,
- diag::expected_member_name);
+ DeclName Name = parseUnqualifiedIdentifier(/*allowInit=*/true,
+ NameLoc,
+ diag::expected_member_name);
if (!Name) return nullptr;
+ // Handle initializers.
+ if (Name.getBaseName() == Context.Id_init) {

This comment has been minimized.

Show comment
Hide comment
@jrose-apple

jrose-apple Jan 21, 2016

Member

We really need to stop treating init and init the same. :-)

@jrose-apple

jrose-apple Jan 21, 2016

Member

We really need to stop treating init and init the same. :-)

+ Expr *initRef = new (Context) UnresolvedConstructorExpr(
+ Result.get(), TokLoc, NameLoc, Name,
+ /*Implicit=*/false);
+ Result = makeParserResult(initRef);
+ continue;
+ }
+
Result = makeParserResult(
new (Context) UnresolvedDotExpr(Result.get(), TokLoc, Name,
- NameLoc, /*Implicit=*/false));
+ NameLoc,
+ /*Implicit=*/false));
if (canParseAsGenericArgumentList()) {
SmallVector<TypeRepr*, 8> args;
View
@@ -1206,8 +1206,6 @@ namespace {
}
Type visitUnresolvedConstructorExpr(UnresolvedConstructorExpr *expr) {
- ASTContext &C = CS.getASTContext();
-
// Open a member constraint for constructor delegations on the subexpr
// type.
if (CS.TC.getSelfForInitDelegationInConstructor(CS.DC, expr)){
@@ -1228,7 +1226,7 @@ namespace {
auto resultTy = CS.createTypeVariable(CS.getConstraintLocator(expr),
/*options=*/0);
auto methodTy = FunctionType::get(argsTy, resultTy);
- CS.addValueMemberConstraint(baseTy, C.Id_init,
+ CS.addValueMemberConstraint(baseTy, expr->getName(),
methodTy,
CS.getConstraintLocator(expr, ConstraintLocator::ConstructorMember));
@@ -1240,7 +1238,7 @@ namespace {
// If we aren't delegating from within an initializer, then 'x.init' is
// just a reference to the constructor as a member of the metatype value
// 'x'.
- return addMemberRefConstraints(expr, expr->getSubExpr(), C.Id_init);
+ return addMemberRefConstraints(expr, expr->getSubExpr(), expr->getName());
}
Type visitDotSyntaxBaseIgnoredExpr(DotSyntaxBaseIgnoredExpr *expr) {
View
@@ -1573,10 +1573,12 @@ swift::createDesignatedInitOverride(TypeChecker &tc,
// Reference to super.init.
Expr *superRef = new (ctx) SuperRefExpr(selfDecl, SourceLoc(),
/*Implicit=*/true);
- Expr *ctorRef = new (ctx) UnresolvedConstructorExpr(superRef,
- SourceLoc(),
- SourceLoc(),
- /*Implicit=*/true);
+ Expr *ctorRef = new (ctx) UnresolvedConstructorExpr(
+ superRef,
+ SourceLoc(),
+ SourceLoc(),
+ superclassCtor->getFullName(),
+ /*Implicit=*/true);
auto ctorArgs = buildArgumentForwardingExpr(bodyParams->getArray(), ctx);
@@ -1187,8 +1187,9 @@ Expr* TypeChecker::constructCallToSuperInit(ConstructorDecl *ctor,
SourceLoc(), /*Implicit=*/true);
Expr *r = new (Context) UnresolvedConstructorExpr(superRef,
SourceLoc(),
- SourceLoc(),
- /*Implicit=*/true);
+ SourceLoc(),
+ Context.Id_init,
+ /*Implicit=*/true);
Expr *args = TupleExpr::createEmpty(Context, SourceLoc(), SourceLoc(),
/*Implicit=*/true);
r = new (Context) CallExpr(r, args, /*Implicit=*/true);
View
@@ -29,7 +29,7 @@ func foo() {
func test3(a: inout Int) {} // expected-error {{'inout' must appear before the parameter name}}{{12-12=inout }}{{15-21=}}
-super.init() // expected-error {{'super' cannot be used outside of class members}} expected-error {{initializers may only be declared within a type}}
+super.init() // expected-error {{'super' cannot be used outside of class members}}
switch state { // expected-error {{use of unresolved identifier 'state'}}
let duration : Int = 0 // expected-error {{all statements inside a switch must be covered by a 'case' or 'default'}} \
@@ -35,12 +35,22 @@ struct S0 {
let s0_static: S0 = .f3(_:y:z:)(0, y: 0, z: 0)
class C0 {
+ init(x: Int, y: Int, z: Int) { }
+
+ convenience init(all: Int) {

This comment has been minimized.

Show comment
Hide comment
@slavapestov

slavapestov Jan 21, 2016

Member

Along the lines of the other review comments, I feel like this test case is not really testing 'unqualified_name's anymore...

@slavapestov

slavapestov Jan 21, 2016

Member

Along the lines of the other review comments, I feel like this test case is not really testing 'unqualified_name's anymore...

+ self.init(x:y:z:)(x: all, y: all, z: all)
+ }
+
func f0(x: Int, y: Int, z: Int) { }
func f1(x: Int, while: Int) { }
func f2(x: Int, `let` _: Int) { }
}
class C1 : C0 {
+ init(all: Int) {
+ super.init(x:y:z:)(x: all, y: all, z: all)
+ }
+
func testC0() {
_ = f0(_:y:z:)
_ = f0(:y:z:) // expected-error{{an empty argument label is spelled with '_'}}{{12-12=_}}

0 comments on commit c9c1d13

Please sign in to comment.