Trying to work out how default parameters work


(Brent Royal-Gordon) #1

My first question is simply this: is this the best place for the sort of question I’m about to ask? Is there an IRC channel or Slack or something where people who are working with Swift’s compiler internals are hanging out? Are people on Twitter (hi, Joe Groff!) going to mind if I pester them with random weird questions about compiler guts?

With the idea in mind that the most important thing I want to find out is “where do I ask things like this?”, here goes.

···

*****

Based on this post <https://lists.swift.org/pipermail/swift-evolution/Week-of-Mon-20151130/000518.html>, I’m trying to make memberwise initializers give default values to parameters which have are initialized in their declaration. This is basically just a quick prototype to (a) learn about how the Swift compiler works, and (b) try to figure out what the implementation issues are going to be like. (For instance, I’ve already noticed that if two properties are declared in the same tuple, it may be difficult to grab their default values.)

My initial approach—which I’m well aware is probably all wrong—is to grab the Expr from the property’s pattern binding and then attach it to the parameter tuple as a default argument. I didn’t see any obvious way to clone an Expr, so I’m basically just using the same instance and hoping for the best.

--- a/lib/Sema/CodeSynthesis.cpp
+++ b/lib/Sema/CodeSynthesis.cpp
@@ -1952,13 +1952,27 @@ ConstructorDecl *swift::createImplicitConstructor(TypeChecker &tc,
      auto *arg = new (context) ParamDecl(/*IsLet*/true, Loc, var->getName(),
                                          Loc, var->getName(), varType, decl);
      arg->setImplicit();
+
+ auto initKind = DefaultArgumentKind::None;
+ ExprHandle * initExpr = nullptr;
+
+ // Is this property's default simple enough to copy?
+ auto *varPatternBinding = var->getParentPatternBinding();
+ if (varPatternBinding && varPatternBinding->getNumPatternEntries() == 1) {
+ auto * init = varPatternBinding->getInit(0);
+ if(init) {
+ initExpr = ExprHandle::get(context, init);
+ initKind = DefaultArgumentKind::Normal;
+ }
+ }
+
      argNames.push_back(var->getName());
      Pattern *pattern = new (context) NamedPattern(arg);
      pattern->setImplicit();
      TypeLoc tyLoc = TypeLoc::withoutLoc(varType);
      pattern = new (context) TypedPattern(pattern, tyLoc);
      patternElts.push_back(TuplePatternElt(var->getName(), SourceLoc(),
- pattern, false));
+ pattern, false, SourceLoc(), initExpr, initKind));
    }
  }

This sort of works in that -dump-ast and -print-ast look right, but when I let the rest of the compiler run, I get a crash half a dozen calls down from SILGenModule::emitDefaultArgGenerator(). Apparently initExpr’s type is null, causing an earth-shattering kaboom.

My working theory is that, because createImplicitConstructor() is called during type checking, some part of the type check, or some earlier pass in the compiler, is not being performed which would normally infer the types of the default values. But I’m really flying blind here, so it could very well be that I’m abusing the AST in some horrible way or missing some step I should obviously be performing. (I did notice, for instance, that the doc comment on ExprHandle is vaguely gesturing at the idea that an expression might be connected to the same AST in two different places.)

So what I’d like to know is:

1) Again, what’s the best venue for these sorts of “I’ve just stumbled into a maze of twisty little passages" questions?
2) Is there any documentation on the AST design in general, or the implementation of TuplePattern and default values in particular, that can help me figure out this part of the code?
3) Does anyone recognize what might be happening here?

Thanks,
--
Brent Royal-Gordon
Architechies


(Joe Groff) #2

My first question is simply this: is this the best place for the sort of question I’m about to ask? Is there an IRC channel or Slack or something where people who are working with Swift’s compiler internals are hanging out? Are people on Twitter (hi, Joe Groff!) going to mind if I pester them with random weird questions about compiler guts?

This is definitely the best place to ask implementation questions. 140 characters isn't great for deep dives on compiler internals.

-Joe

···

On Dec 8, 2015, at 2:43 AM, Brent Royal-Gordon via swift-dev <swift-dev@swift.org> wrote:

With the idea in mind that the most important thing I want to find out is “where do I ask things like this?”, here goes.

*****

Based on this post <https://lists.swift.org/pipermail/swift-evolution/Week-of-Mon-20151130/000518.html>, I’m trying to make memberwise initializers give default values to parameters which have are initialized in their declaration. This is basically just a quick prototype to (a) learn about how the Swift compiler works, and (b) try to figure out what the implementation issues are going to be like. (For instance, I’ve already noticed that if two properties are declared in the same tuple, it may be difficult to grab their default values.)

My initial approach—which I’m well aware is probably all wrong—is to grab the Expr from the property’s pattern binding and then attach it to the parameter tuple as a default argument. I didn’t see any obvious way to clone an Expr, so I’m basically just using the same instance and hoping for the best.

--- a/lib/Sema/CodeSynthesis.cpp
+++ b/lib/Sema/CodeSynthesis.cpp
@@ -1952,13 +1952,27 @@ ConstructorDecl *swift::createImplicitConstructor(TypeChecker &tc,
     auto *arg = new (context) ParamDecl(/*IsLet*/true, Loc, var->getName(),
                                         Loc, var->getName(), varType, decl);
     arg->setImplicit();
+
+ auto initKind = DefaultArgumentKind::None;
+ ExprHandle * initExpr = nullptr;
+
+ // Is this property's default simple enough to copy?
+ auto *varPatternBinding = var->getParentPatternBinding();
+ if (varPatternBinding && varPatternBinding->getNumPatternEntries() == 1) {
+ auto * init = varPatternBinding->getInit(0);
+ if(init) {
+ initExpr = ExprHandle::get(context, init);
+ initKind = DefaultArgumentKind::Normal;
+ }
+ }
+
     argNames.push_back(var->getName());
     Pattern *pattern = new (context) NamedPattern(arg);
     pattern->setImplicit();
     TypeLoc tyLoc = TypeLoc::withoutLoc(varType);
     pattern = new (context) TypedPattern(pattern, tyLoc);
     patternElts.push_back(TuplePatternElt(var->getName(), SourceLoc(),
- pattern, false));
+ pattern, false, SourceLoc(), initExpr, initKind));
   }
}

This sort of works in that -dump-ast and -print-ast look right, but when I let the rest of the compiler run, I get a crash half a dozen calls down from SILGenModule::emitDefaultArgGenerator(). Apparently initExpr’s type is null, causing an earth-shattering kaboom.

My working theory is that, because createImplicitConstructor() is called during type checking, some part of the type check, or some earlier pass in the compiler, is not being performed which would normally infer the types of the default values. But I’m really flying blind here, so it could very well be that I’m abusing the AST in some horrible way or missing some step I should obviously be performing. (I did notice, for instance, that the doc comment on ExprHandle is vaguely gesturing at the idea that an expression might be connected to the same AST in two different places.)

So what I’d like to know is:

1) Again, what’s the best venue for these sorts of “I’ve just stumbled into a maze of twisty little passages" questions?
2) Is there any documentation on the AST design in general, or the implementation of TuplePattern and default values in particular, that can help me figure out this part of the code?
3) Does anyone recognize what might be happening here?

Thanks,
--
Brent Royal-Gordon
Architechies

_______________________________________________
swift-dev mailing list
swift-dev@swift.org
https://lists.swift.org/mailman/listinfo/swift-dev