Introduce "inherited" default arguments and use them for inherited initializers.

Previously, we were cloning the default arguments completely, which
meant code duplication (when inheriting within a module) or simply a
failure (when inheriting across modules). Now, we reference the
default arguments where we inherited them, eliminating the
duplication. Part of <rdar://problem/16318855>.

Swift SVN r15062
This commit is contained in:
Doug Gregor
2014-03-14 18:31:22 +00:00
parent 8cf018a1d2
commit d32f668fb2
10 changed files with 106 additions and 12 deletions

View File

@@ -25,6 +25,9 @@ enum class DefaultArgumentKind {
None,
/// A normal default argument.
Normal,
/// The default argument is inherited from the corresponding argument of the
/// overridden declaration.
Inherited,
/// The __FILE__ default argument, which is expanded at the call site.
File,
/// The __LINE__ default argument, which is expanded at the call site.

View File

@@ -139,7 +139,11 @@ public:
/// Flags used to indicate how pattern cloning should operate.
enum CloneFlags {
/// The cloned pattern should be implicit.
Implicit = 0x01,
/// The cloned pattern is for an inherited constructor; mark default
/// arguments as inherited.
Inherited = 0x02
};
Pattern *clone(ASTContext &context,

View File

@@ -910,6 +910,8 @@ class TupleTypeElt {
VarArg,
/// It has a normal default argument.
DefaultArgument,
/// It has an inherited default argument.
InheritedDefaultArgument,
/// It has a caller-provided __FILE__ default argument.
FileArgument,
/// It has a caller-provided __LINE__ default argument.
@@ -955,6 +957,8 @@ public:
return DefaultArgumentKind::None;
case DefaultArgOrVarArg::DefaultArgument:
return DefaultArgumentKind::Normal;
case DefaultArgOrVarArg::InheritedDefaultArgument:
return DefaultArgumentKind::Inherited;
case DefaultArgOrVarArg::FileArgument:
return DefaultArgumentKind::File;
case DefaultArgOrVarArg::LineArgument:
@@ -3287,6 +3291,10 @@ inline TupleTypeElt::TupleTypeElt(Type ty,
TyAndDefaultOrVarArg.setInt(DefaultArgOrVarArg::DefaultArgument);
break;
case DefaultArgumentKind::Inherited:
TyAndDefaultOrVarArg.setInt(DefaultArgOrVarArg::InheritedDefaultArgument);
break;
case DefaultArgumentKind::File:
TyAndDefaultOrVarArg.setInt(DefaultArgOrVarArg::FileArgument);
break;

View File

@@ -177,6 +177,7 @@ enum DefaultArgumentKind : uint8_t {
Line,
Column,
Function,
Inherited,
};
using DefaultArgumentField = BCFixed<3>;

View File

@@ -222,10 +222,21 @@ Pattern *Pattern::clone(ASTContext &context,
auto tuple = cast<TuplePattern>(this);
SmallVector<TuplePatternElt, 2> elts;
elts.reserve(tuple->getNumFields());
for (const auto &elt : tuple->getFields())
elts.push_back(TuplePatternElt(elt.getPattern()->clone(context, options),
for (const auto &elt : tuple->getFields()) {
auto eltPattern = elt.getPattern()->clone(context, options);
// If we're inheriting a default argument, mark it as such.
if (elt.getDefaultArgKind() != DefaultArgumentKind::None &&
(options & Inherited)) {
elts.push_back(TuplePatternElt(eltPattern, nullptr,
DefaultArgumentKind::Inherited));
} else {
elts.push_back(TuplePatternElt(eltPattern,
elt.getInit(),
elt.getDefaultArgKind()));
}
}
result = TuplePattern::create(context, tuple->getLParenLoc(), elts,
tuple->getRParenLoc(),
tuple->hasVararg(),

View File

@@ -2372,7 +2372,7 @@ findDefaultArgsOwner(ConstraintSystem &cs, const Solution &solution,
/// Produce the caller-side default argument for this default argument, or
/// null if the default argument will be provided by the callee.
static Expr *getCallerDefaultArg(TypeChecker &tc, DeclContext *dc,
SourceLoc loc, AbstractFunctionDecl *owner,
SourceLoc loc, AbstractFunctionDecl *&owner,
unsigned index) {
auto defArg = owner->getDefaultArg(index);
MagicIdentifierLiteralExpr::Kind magicKind;
@@ -2383,6 +2383,11 @@ static Expr *getCallerDefaultArg(TypeChecker &tc, DeclContext *dc,
case DefaultArgumentKind::Normal:
return nullptr;
case DefaultArgumentKind::Inherited:
// Update the owner to reflect inheritance here.
owner = owner->getOverriddenDecl();
return getCallerDefaultArg(tc, dc, loc, owner, index);
case DefaultArgumentKind::Column:
magicKind = MagicIdentifierLiteralExpr::Column;
break;

View File

@@ -3942,10 +3942,73 @@ createSubobjectInitOverride(TypeChecker &tc,
selfBodyPattern = new (ctx) TypedPattern(selfBodyPattern, TypeLoc());
// Create the initializer parameter patterns.
OptionSet<Pattern::CloneFlags> options;
options |= Pattern::Implicit;
options |= Pattern::Inherited;
Pattern *argParamPatterns
= superclassCtor->getArgParamPatterns()[1]->clone(ctx, Pattern::Implicit);
= superclassCtor->getArgParamPatterns()[1]->clone(ctx, options);
Pattern *bodyParamPatterns
= superclassCtor->getBodyParamPatterns()[1]->clone(ctx, Pattern::Implicit);
= superclassCtor->getBodyParamPatterns()[1]->clone(ctx, options);
// Fix up the default arguments in the type to refer to inherited default
// arguments.
// FIXME: If we weren't cloning the type along with the pattern, this would be
// a lot more direct.
Type argType = argParamPatterns->getType();
// Local function that maps default arguments to inherited default arguments.
std::function<Type(Type)> inheritDefaultArgs = [&](Type type) -> Type {
auto tuple = type->getAs<TupleType>();
if (!tuple)
return type;
bool anyChanged = false;
SmallVector<TupleTypeElt, 4> elements;
unsigned index = 0;
for (const auto &elt : tuple->getFields()) {
Type eltTy = elt.getType().transform(inheritDefaultArgs);
if (!eltTy)
return Type();
// If nothing has changd, just keep going.
if (!anyChanged && eltTy.getPointer() == elt.getType().getPointer() &&
(elt.getDefaultArgKind() == DefaultArgumentKind::None ||
elt.getDefaultArgKind() == DefaultArgumentKind::Inherited)) {
++index;
continue;
}
// If this is the first change we've seen, copy all of the previous
// elements.
if (!anyChanged) {
// Copy all of the previous elements.
for (unsigned i = 0; i != index; ++i) {
const TupleTypeElt &FromElt =tuple->getFields()[i];
elements.push_back(TupleTypeElt(FromElt.getType(), FromElt.getName(),
FromElt.getDefaultArgKind(),
FromElt.isVararg()));
}
anyChanged = true;
}
// Add the new tuple element, with the new type, no initializer,
auto defaultArgKind = elt.getDefaultArgKind();
if (defaultArgKind != DefaultArgumentKind::None)
defaultArgKind = DefaultArgumentKind::Inherited;
elements.push_back(TupleTypeElt(eltTy, elt.getName(), defaultArgKind,
elt.isVararg()));
++index;
}
if (!anyChanged)
return type;
return TupleType::get(elements, ctx);
};
argType = argType.transform(inheritDefaultArgs);
argParamPatterns->setType(argType);
// Create the initializer declaration.
auto ctor = new (ctx) ConstructorDecl(ctx.Id_init, SourceLoc(),

View File

@@ -653,11 +653,6 @@ static void checkDefaultArguments(TypeChecker &tc, Pattern *pattern,
unsigned curArgIndex = nextArgIndex++;
if (field.getInit()) {
// FIXME: cloned default arguments should have a different
// representation.
if (field.getInit()->alreadyChecked())
continue;
Expr *e = field.getInit()->getExpr();
// Re-use an existing initializer context if possible.

View File

@@ -192,6 +192,8 @@ getActualDefaultArgKind(uint8_t raw) {
return swift::DefaultArgumentKind::None;
case serialization::DefaultArgumentKind::Normal:
return swift::DefaultArgumentKind::Normal;
case serialization::DefaultArgumentKind::Inherited:
return swift::DefaultArgumentKind::Inherited;
case serialization::DefaultArgumentKind::Column:
return swift::DefaultArgumentKind::Column;
case serialization::DefaultArgumentKind::File:

View File

@@ -471,6 +471,8 @@ static uint8_t getRawStableDefaultArgumentKind(swift::DefaultArgumentKind kind)
return serialization::DefaultArgumentKind::None;
case swift::DefaultArgumentKind::Normal:
return serialization::DefaultArgumentKind::Normal;
case swift::DefaultArgumentKind::Inherited:
return serialization::DefaultArgumentKind::Inherited;
case swift::DefaultArgumentKind::Column:
return serialization::DefaultArgumentKind::Column;
case swift::DefaultArgumentKind::File: