Skip to content

[SE-0155] Implement (Most of) The Proposal #15418

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion include/swift/AST/ASTMangler.h
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ class ASTMangler : public Mangler {
std::string mangleGlobalGetterEntity(const ValueDecl *decl,
SymbolKind SKind = SymbolKind::Default);

std::string mangleDefaultArgumentEntity(const DeclContext *func,
std::string mangleDefaultArgumentEntity(const ValueDecl *decl,
unsigned index,
SymbolKind SKind);

Expand Down
24 changes: 24 additions & 0 deletions include/swift/AST/DiagnosticsSema.def
Original file line number Diff line number Diff line change
Expand Up @@ -3223,6 +3223,12 @@ ERROR(type_pattern_missing_is,none,
ERROR(pattern_type_mismatch_context,none,
"type annotation does not match contextual type %0", (Type))

ERROR(paren_pattern_in_tuple_context,none,
"parenthesized pattern cannot match value of tuple type %0", (Type))
WARNING(paren_pattern_in_tuple_context_warn_swift3,none,
"parenthesized pattern matches value of tuple type %0; this may be "
"unintended and will be removed in a future version of Swift", (Type))

ERROR(tuple_pattern_in_non_tuple_context,none,
"tuple pattern cannot match values of the non-tuple type %0", (Type))
ERROR(closure_argument_list_tuple,none,
Expand Down Expand Up @@ -3250,10 +3256,18 @@ ERROR(enum_element_pattern_assoc_values_mismatch,none,
(Identifier))
NOTE(enum_element_pattern_assoc_values_remove,none,
"remove associated values to make the pattern match", ())

ERROR(tuple_pattern_length_mismatch,none,
"tuple pattern has the wrong length for tuple type %0", (Type))
ERROR(tuple_pattern_label_mismatch,none,
"tuple pattern element label %0 must be %1", (Identifier, Identifier))
ERROR(tuple_pattern_label_missing,none,
"tuple pattern mentioning element labels must also specify label '%0'",
(Identifier))
ERROR(tuple_pattern_label_should_be_elided,none,
"tuple pattern not mentioning element labels may not specify label %0",
(Identifier))

ERROR(enum_element_pattern_member_not_found,none,
"enum case '%0' not found in type %1", (StringRef, Type))
ERROR(optional_element_pattern_not_valid_type,none,
Expand Down Expand Up @@ -3284,6 +3298,16 @@ ERROR(isa_collection_downcast_pattern_value_unimplemented,none,
"collection downcast in cast pattern is not implemented; use an explicit "
"downcast to %0 instead", (Type))

WARNING(swift3_ignore_specialized_enum_element_call,none,
"cannot specialize enum case; ignoring generic argument, "
"which will be rejected in future version of Swift", ())

ERROR(ambiguous_enum_element_in_pattern,none,
"enum case %0 is ambiguous without explicit pattern matching "
"associated values", (Identifier))
NOTE(ambiguous_enum_element_candidate,none,
"found potentially matching case %0", (DeclName))

//------------------------------------------------------------------------------
// MARK: Error-handling diagnostics
//------------------------------------------------------------------------------
Expand Down
8 changes: 6 additions & 2 deletions lib/AST/ASTMangler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -159,11 +159,15 @@ std::string ASTMangler::mangleGlobalGetterEntity(const ValueDecl *decl,
return finalize();
}

std::string ASTMangler::mangleDefaultArgumentEntity(const DeclContext *func,
std::string ASTMangler::mangleDefaultArgumentEntity(const ValueDecl *decl,
unsigned index,
SymbolKind SKind) {
beginMangling();
appendDefaultArgumentEntity(func, index);
if (auto *AFD = dyn_cast<AbstractFunctionDecl>(decl)) {
appendDefaultArgumentEntity(AFD, index);
} else {
appendDefaultArgumentEntity(decl->getDeclContext(), index);
}
appendSymbolKind(SKind);
return finalize();
}
Expand Down
3 changes: 3 additions & 0 deletions lib/AST/DeclContext.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -285,6 +285,9 @@ ResilienceExpansion DeclContext::getResilienceExpansion() const {
// Default argument initializer contexts have their resilience expansion
// set when they're type checked.
if (isa<DefaultArgumentInitializer>(dc)) {
if (auto *ED = dyn_cast<EnumDecl>(dc->getParent())) {
return ED->getResilienceExpansion();
}
return cast<AbstractFunctionDecl>(dc->getParent())
->getDefaultArgumentResilienceExpansion();
}
Expand Down
6 changes: 2 additions & 4 deletions lib/Parse/ParsePattern.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,7 @@ static ParserStatus parseDefaultArgument(
case Parser::ParameterContextKind::Function:
case Parser::ParameterContextKind::Operator:
case Parser::ParameterContextKind::Initializer:
case Parser::ParameterContextKind::EnumElement:
break;
case Parser::ParameterContextKind::Closure:
diagID = diag::no_default_arg_closure;
Expand All @@ -101,9 +102,6 @@ static ParserStatus parseDefaultArgument(
case Parser::ParameterContextKind::Curried:
diagID = diag::no_default_arg_curried;
break;
case Parser::ParameterContextKind::EnumElement:
diagID = diag::no_default_arg_enum_elt;
break;
}

assert((diagID.ID != DiagID()) == !defaultArgs &&
Expand Down Expand Up @@ -409,7 +407,7 @@ validateParameterWithSpecifier(Parser &parser,
if (parsingEnumElt) {
return new (parser.Context) T(type, loc);
}

if (isa<SpecifierTypeRepr>(type)) {
parser.diagnose(loc, diag::parameter_specifier_repeated).fixItRemove(loc);
} else {
Expand Down
16 changes: 10 additions & 6 deletions lib/SIL/SILDeclRef.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -451,8 +451,14 @@ IsSerialized_t SILDeclRef::isSerialized() const {
// Default argument generators are serialized if the function was
// type-checked in Swift 4 mode.
if (kind == SILDeclRef::Kind::DefaultArgGenerator) {
auto *afd = cast<AbstractFunctionDecl>(d);
switch (afd->getDefaultArgumentResilienceExpansion()) {
ResilienceExpansion expansion;
if (auto *EED = dyn_cast<EnumElementDecl>(d)) {
expansion = EED->getDefaultArgumentResilienceExpansion();
} else {
expansion = cast<AbstractFunctionDecl>(d)
->getDefaultArgumentResilienceExpansion();
}
switch (expansion) {
case ResilienceExpansion::Minimal:
return IsSerialized;
case ResilienceExpansion::Maximal:
Expand Down Expand Up @@ -708,10 +714,8 @@ std::string SILDeclRef::mangle(ManglingKind MKind) const {

case SILDeclRef::Kind::DefaultArgGenerator:
assert(!isCurried);
return mangler.mangleDefaultArgumentEntity(
cast<AbstractFunctionDecl>(getDecl()),
defaultArgIndex,
SKind);
return mangler.mangleDefaultArgumentEntity(getDecl(), defaultArgIndex,
SKind);

case SILDeclRef::Kind::StoredPropertyInitializer:
assert(!isCurried);
Expand Down
29 changes: 27 additions & 2 deletions lib/SIL/SILVerifier.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -509,6 +509,31 @@ class SILVerifier : public SILVerifierBase<SILVerifier> {
llvm::dbgs() << " " << type1 << "\n " << type2 << '\n';
});
}

/// Assert that two payload types are equal.
void requireSamePayloadType(SILType type1, SILType type2,
const Twine &complaint) {
if (auto tuple1 = dyn_cast<TupleType>(type1.getSwiftRValueType())) {
require(type2.is<TupleType>(),
"Second payload type does not match first tuple type payload!");

auto tuple2 = type2.castTo<TupleType>();

require(tuple1->getElements().size() == tuple2->getNumElements(),
"Payload tuple element count mismatch!");

for (size_t i = 0, size = tuple1->getElements().size(); i < size; ++i) {
_require(tuple1.getElementType(i) == tuple2.getElementType(i),
complaint, [&] {
llvm::dbgs() << " " << type1 << "\n " << type2 << '\n';
});
}
} else {
_require(type1 == type2, complaint, [&] {
llvm::dbgs() << " " << type1 << "\n " << type2 << '\n';
});
}
}

/// Require two function types to be ABI-compatible.
void requireABICompatibleFunctionTypes(CanSILFunctionType type1,
Expand Down Expand Up @@ -2090,7 +2115,7 @@ class SILVerifier : public SILVerifierBase<SILVerifier> {
SILType caseTy = UI->getType().getEnumElementType(UI->getElement(),
F.getModule());
if (UI->getModule().getStage() != SILStage::Lowered) {
require(caseTy == UI->getOperand()->getType(),
requireSamePayloadType(caseTy, UI->getOperand()->getType(),
"EnumInst operand type does not match type of case");
}
}
Expand Down Expand Up @@ -3922,7 +3947,7 @@ class SILVerifier : public SILVerifierBase<SILVerifier> {
if (F.getModule().getStage() != SILStage::Lowered) {
// During the lowered stage, a function type might have different
// signature
require(eltArgTy == bbArgTy,
requireSamePayloadType(eltArgTy, bbArgTy,
"switch_enum destination bbarg must match case arg type");
}
require(!dest->getArguments()[0]->getType().isAddress(),
Expand Down
3 changes: 3 additions & 0 deletions lib/SILGen/SILGen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -832,6 +832,9 @@ void SILGenModule::emitConstructor(ConstructorDecl *decl) {
void SILGenModule::emitEnumConstructor(EnumElementDecl *decl) {
// Enum element constructors are always emitted by need, so don't need
// delayed emission.
if (auto params = decl->getParameterList())
emitDefaultArgGenerators(decl, params);

SILDeclRef constant(decl);
SILFunction *f = getFunction(constant, ForDefinition);
preEmitFunction(constant, decl, f, decl);
Expand Down
11 changes: 7 additions & 4 deletions lib/SILGen/SILGenApply.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -580,13 +580,13 @@ class Callee {
assert(Substitutions.empty());
return IndirectValue;

case Kind::EnumElement:
LLVM_FALLTHROUGH;
case Kind::StandaloneFunction: {
auto constantInfo = SGF.getConstantInfo(*constant);
SILValue ref = SGF.emitGlobalFunctionRef(Loc, *constant, constantInfo);
return ManagedValue::forUnmanaged(ref);
}
case Kind::EnumElement:
llvm_unreachable("Should have been curried");
case Kind::ClassMethod: {
auto methodTy = SGF.SGM.Types.getConstantOverrideType(*constant);

Expand Down Expand Up @@ -683,8 +683,11 @@ class Callee {
auto constantInfo = SGF.getConstantInfo(*constant);
return createCalleeTypeInfo(SGF, constant, constantInfo.getSILType());
}
case Kind::EnumElement:
llvm_unreachable("Should have been curried");
case Kind::EnumElement: {
// Emit a direct call to the element constructor thunk.
auto constantInfo = SGF.getConstantInfo(*constant);
return createCalleeTypeInfo(SGF, constant, constantInfo.getSILType());
}
case Kind::ClassMethod: {
auto constantInfo = SGF.SGM.Types.getConstantOverrideInfo(*constant);
return createCalleeTypeInfo(SGF, constant, constantInfo.getSILType());
Expand Down
3 changes: 3 additions & 0 deletions lib/SILGen/SILGenFunction.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,9 @@ DeclName SILGenModule::getMagicFunctionName(SILDeclRef ref) {
case SILDeclRef::Kind::GlobalAccessor:
return getMagicFunctionName(cast<VarDecl>(ref.getDecl())->getDeclContext());
case SILDeclRef::Kind::DefaultArgGenerator:
if (auto *ED = dyn_cast<EnumElementDecl>(ref.getDecl())) {
return ED->getFullName();
}
return getMagicFunctionName(cast<AbstractFunctionDecl>(ref.getDecl()));
case SILDeclRef::Kind::StoredPropertyInitializer:
return getMagicFunctionName(cast<VarDecl>(ref.getDecl())->getDeclContext());
Expand Down
9 changes: 8 additions & 1 deletion lib/Sema/CSApply.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4954,7 +4954,14 @@ getCallerDefaultArg(ConstraintSystem &cs, DeclContext *dc,
unsigned index) {
auto &tc = cs.getTypeChecker();

auto defArg = getDefaultArgumentInfo(cast<ValueDecl>(owner.getDecl()), index);
std::pair<DefaultArgumentKind, Type> defArg;
if (auto *AFD = dyn_cast<AbstractFunctionDecl>(owner.getDecl())) {
defArg = getDefaultArgumentInfo(AFD->getParameters(), index);
} else {
defArg = getDefaultArgumentInfo(
cast<EnumElementDecl>(owner.getDecl())->getParameterList(),
index);
}
Expr *init = nullptr;
switch (defArg.first) {
case DefaultArgumentKind::None:
Expand Down
30 changes: 22 additions & 8 deletions lib/Sema/CSRanking.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -373,15 +373,14 @@ static bool paramIsIUO(Decl *decl, int paramNum) {
auto *paramList = fn->getParameters();
auto *param = paramList->get(paramNum);
return param->getAttrs().hasAttribute<ImplicitlyUnwrappedOptionalAttr>();
} else if (auto *subscript = dyn_cast<SubscriptDecl>(decl)) {
auto *index = subscript->getIndices()->get(paramNum);
return index->getAttrs().hasAttribute<ImplicitlyUnwrappedOptionalAttr>();
} else {
auto *enumElt = cast<EnumElementDecl>(decl);
auto *index = enumElt->getParameterList()->get(paramNum);
return index->getAttrs().hasAttribute<ImplicitlyUnwrappedOptionalAttr>();
}
if (auto *ee = dyn_cast<EnumElementDecl>(decl)) {
auto *param = ee->getParameterList()->get(paramNum);
return param->getAttrs().hasAttribute<ImplicitlyUnwrappedOptionalAttr>();
}

auto *subscript = cast<SubscriptDecl>(decl);
auto *index = subscript->getIndices()->get(paramNum);
return index->getAttrs().hasAttribute<ImplicitlyUnwrappedOptionalAttr>();
}

/// \brief Determine whether the first declaration is as "specialized" as
Expand Down Expand Up @@ -632,6 +631,21 @@ static bool isDeclAsSpecializedAs(TypeChecker &tc, DeclContext *dc,
break;

case CheckInput: {
if (auto *ED1 = dyn_cast<EnumElementDecl>(decl1)) {
if (auto *ED2 = dyn_cast<EnumElementDecl>(decl2)) {
assert(ED1->hasAssociatedValues() || ED2->hasAssociatedValues());

// If the first function has fewer effective parameters than the
// second, it is more specialized.
if (!ED1->hasAssociatedValues() && ED2->hasAssociatedValues())
return true;
if (ED1->hasAssociatedValues() && !ED2->hasAssociatedValues())
return false;

// Else, fall through to compare function type specialization.
}
}

// Check whether the first function type's input is a subtype of the
// second type's inputs, i.e., can we forward the arguments?
auto funcTy1 = openedType1->castTo<FunctionType>();
Expand Down
Loading