mirror of
https://github.com/apple/swift.git
synced 2025-12-21 12:14:44 +01:00
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:
@@ -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.
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -177,6 +177,7 @@ enum DefaultArgumentKind : uint8_t {
|
||||
Line,
|
||||
Column,
|
||||
Function,
|
||||
Inherited,
|
||||
};
|
||||
using DefaultArgumentField = BCFixed<3>;
|
||||
|
||||
|
||||
@@ -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(),
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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(),
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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:
|
||||
|
||||
Reference in New Issue
Block a user