Skip to content

Commit 80123bd

Browse files
author
Greg Titus
committed
Improve diagnoses of generic specializations
Always add constraints, find fixes during simplify. New separate fix for allow generic function specialization. Improve parse heuristic for isGenericTypeDisambiguatingToken. Degrade concrete type specialization fix to warning for macros.
1 parent 66e6c00 commit 80123bd

19 files changed

+225
-106
lines changed

include/swift/AST/DiagnosticsSema.def

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4605,8 +4605,6 @@ NOTE(duplicated_key_declared_here, none,
46054605
// Generic specializations
46064606
ERROR(cannot_explicitly_specialize_generic_function,none,
46074607
"cannot explicitly specialize a generic function", ())
4608-
ERROR(not_a_generic_definition,none,
4609-
"cannot specialize a non-generic definition", ())
46104608
ERROR(not_a_generic_type,none,
46114609
"cannot specialize non-generic type %0", (Type))
46124610
ERROR(protocol_declares_unknown_primary_assoc_type,none,

include/swift/AST/Types.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7327,7 +7327,7 @@ class PlaceholderType : public TypeBase {
73277327
// recursive property logic in PlaceholderType::get.
73287328
using Originator =
73297329
llvm::PointerUnion<TypeVariableType *, DependentMemberType *, VarDecl *,
7330-
ErrorExpr *, PlaceholderTypeRepr *>;
7330+
ErrorExpr *, TypeRepr *>;
73317331

73327332
Originator O;
73337333

include/swift/Sema/CSFix.h

Lines changed: 39 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -462,9 +462,12 @@ enum class FixKind : uint8_t {
462462
/// because its name doesn't appear in 'initializes' or 'accesses' attributes.
463463
AllowInvalidMemberReferenceInInitAccessor,
464464

465-
/// Ignore an attempt to specialize non-generic type.
465+
/// Ignore an attempt to specialize a non-generic type.
466466
AllowConcreteTypeSpecialization,
467467

468+
/// Ignore an attempt to specialize a generic function.
469+
AllowGenericFunctionSpecialization,
470+
468471
/// Ignore an out-of-place \c then statement.
469472
IgnoreOutOfPlaceThenStmt,
470473

@@ -3720,8 +3723,10 @@ class AllowConcreteTypeSpecialization final : public ConstraintFix {
37203723
Type ConcreteType;
37213724

37223725
AllowConcreteTypeSpecialization(ConstraintSystem &cs, Type concreteTy,
3723-
ConstraintLocator *locator)
3724-
: ConstraintFix(cs, FixKind::AllowConcreteTypeSpecialization, locator),
3726+
ConstraintLocator *locator,
3727+
FixBehavior fixBehavior)
3728+
: ConstraintFix(cs, FixKind::AllowConcreteTypeSpecialization, locator,
3729+
fixBehavior),
37253730
ConcreteType(concreteTy) {}
37263731

37273732
public:
@@ -3735,14 +3740,43 @@ class AllowConcreteTypeSpecialization final : public ConstraintFix {
37353740
return diagnose(*commonFixes.front().first);
37363741
}
37373742

3738-
static AllowConcreteTypeSpecialization *
3739-
create(ConstraintSystem &cs, Type concreteTy, ConstraintLocator *locator);
3743+
static AllowConcreteTypeSpecialization *create(ConstraintSystem &cs,
3744+
Type concreteTy,
3745+
ConstraintLocator *locator,
3746+
FixBehavior fixBehavior);
37403747

37413748
static bool classof(const ConstraintFix *fix) {
37423749
return fix->getKind() == FixKind::AllowConcreteTypeSpecialization;
37433750
}
37443751
};
37453752

3753+
class AllowGenericFunctionSpecialization final : public ConstraintFix {
3754+
ValueDecl *Decl;
3755+
3756+
AllowGenericFunctionSpecialization(ConstraintSystem &cs, ValueDecl *decl,
3757+
ConstraintLocator *locator)
3758+
: ConstraintFix(cs, FixKind::AllowGenericFunctionSpecialization, locator),
3759+
Decl(decl) {}
3760+
3761+
public:
3762+
std::string getName() const override {
3763+
return "allow generic function specialization";
3764+
}
3765+
3766+
bool diagnose(const Solution &solution, bool asNote = false) const override;
3767+
3768+
bool diagnoseForAmbiguity(CommonFixesArray commonFixes) const override {
3769+
return diagnose(*commonFixes.front().first);
3770+
}
3771+
3772+
static AllowGenericFunctionSpecialization *
3773+
create(ConstraintSystem &cs, ValueDecl *decl, ConstraintLocator *locator);
3774+
3775+
static bool classof(const ConstraintFix *fix) {
3776+
return fix->getKind() == FixKind::AllowGenericFunctionSpecialization;
3777+
}
3778+
};
3779+
37463780
class IgnoreOutOfPlaceThenStmt final : public ConstraintFix {
37473781
IgnoreOutOfPlaceThenStmt(ConstraintSystem &cs, ConstraintLocator *locator)
37483782
: ConstraintFix(cs, FixKind::IgnoreOutOfPlaceThenStmt, locator) {}

include/swift/Sema/ConstraintLocator.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -985,13 +985,13 @@ class LocatorPathElt::ConformanceRequirement final
985985
};
986986

987987
class LocatorPathElt::PlaceholderType final
988-
: public StoredPointerElement<PlaceholderTypeRepr> {
988+
: public StoredPointerElement<TypeRepr> {
989989
public:
990-
PlaceholderType(PlaceholderTypeRepr *placeholderRepr)
990+
PlaceholderType(TypeRepr *placeholderRepr)
991991
: StoredPointerElement(PathElementKind::PlaceholderType,
992992
placeholderRepr) {}
993993

994-
PlaceholderTypeRepr *getPlaceholderRepr() const { return getStoredPointer(); }
994+
TypeRepr *getPlaceholderRepr() const { return getStoredPointer(); }
995995

996996
static bool classof(const LocatorPathElt *elt) {
997997
return elt->getKind() == ConstraintLocator::PlaceholderType;

lib/AST/ASTDumper.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3987,8 +3987,8 @@ namespace {
39873987
printFlag("error_expr");
39883988
} else if (auto *DMT = originator.dyn_cast<DependentMemberType *>()) {
39893989
printRec(DMT, "dependent_member_type");
3990-
} else if (originator.is<PlaceholderTypeRepr *>()) {
3991-
printFlag("placeholder_type_repr");
3990+
} else if (originator.is<TypeRepr *>()) {
3991+
printFlag("type_repr");
39923992
} else {
39933993
assert(false && "unknown originator");
39943994
}

lib/AST/ASTPrinter.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5870,8 +5870,8 @@ class TypePrinter : public TypeVisitor<TypePrinter> {
58705870
Printer << "error_expr";
58715871
} else if (auto *DMT = originator.dyn_cast<DependentMemberType *>()) {
58725872
visit(DMT);
5873-
} else if (originator.is<PlaceholderTypeRepr *>()) {
5874-
Printer << "placeholder_type_repr";
5873+
} else if (originator.is<TypeRepr *>()) {
5874+
Printer << "type_repr";
58755875
} else {
58765876
assert(false && "unknown originator");
58775877
}

lib/Parse/ParseType.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1476,7 +1476,9 @@ static bool isGenericTypeDisambiguatingToken(Parser &P) {
14761476
auto &tok = P.Tok;
14771477
switch (tok.getKind()) {
14781478
default:
1479-
return false;
1479+
// If this is the end of the expr (wouldn't match parseExprSequenceElement),
1480+
// prefer generic type list over an illegal unary postfix '>' operator.
1481+
return P.isStartOfSwiftDecl() || P.isStartOfStmt(/*prefer expr=*/true);
14801482
case tok::r_paren:
14811483
case tok::r_square:
14821484
case tok::l_brace:

lib/Sema/CSDiagnostics.cpp

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9364,6 +9364,16 @@ bool ConcreteTypeSpecialization::diagnoseAsError() {
93649364
return true;
93659365
}
93669366

9367+
bool GenericFunctionSpecialization::diagnoseAsError() {
9368+
emitDiagnostic(diag::cannot_explicitly_specialize_generic_function);
9369+
return true;
9370+
}
9371+
9372+
bool MacroSpecialization::diagnoseAsError() {
9373+
emitDiagnostic(diag::cannot_specialize_macro);
9374+
return true;
9375+
}
9376+
93679377
bool OutOfPlaceThenStmtFailure::diagnoseAsError() {
93689378
emitDiagnostic(diag::out_of_place_then_stmt);
93699379
return true;

lib/Sema/CSDiagnostics.h

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3130,13 +3130,36 @@ class ConcreteTypeSpecialization final : public FailureDiagnostic {
31303130

31313131
public:
31323132
ConcreteTypeSpecialization(const Solution &solution, Type concreteTy,
3133-
ConstraintLocator *locator)
3134-
: FailureDiagnostic(solution, locator),
3133+
ConstraintLocator *locator,
3134+
FixBehavior fixBehavior)
3135+
: FailureDiagnostic(solution, locator, fixBehavior),
31353136
ConcreteType(resolveType(concreteTy)) {}
31363137

31373138
bool diagnoseAsError() override;
31383139
};
31393140

3141+
class GenericFunctionSpecialization final : public FailureDiagnostic {
3142+
ValueDecl *Decl;
3143+
3144+
public:
3145+
GenericFunctionSpecialization(const Solution &solution, ValueDecl *decl,
3146+
ConstraintLocator *locator)
3147+
: FailureDiagnostic(solution, locator), Decl(decl) {}
3148+
3149+
bool diagnoseAsError() override;
3150+
};
3151+
3152+
class MacroSpecialization final : public FailureDiagnostic {
3153+
ValueDecl *Decl;
3154+
3155+
public:
3156+
MacroSpecialization(const Solution &solution, ValueDecl *decl,
3157+
ConstraintLocator *locator)
3158+
: FailureDiagnostic(solution, locator), Decl(decl) {}
3159+
3160+
bool diagnoseAsError() override;
3161+
};
3162+
31403163
/// Diagnose an out-of-place ThenStmt.
31413164
class OutOfPlaceThenStmtFailure final : public FailureDiagnostic {
31423165
public:

lib/Sema/CSFix.cpp

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2605,15 +2605,29 @@ AllowInvalidMemberReferenceInInitAccessor::create(ConstraintSystem &cs,
26052605

26062606
bool AllowConcreteTypeSpecialization::diagnose(const Solution &solution,
26072607
bool asNote) const {
2608-
ConcreteTypeSpecialization failure(solution, ConcreteType, getLocator());
2608+
ConcreteTypeSpecialization failure(solution, ConcreteType, getLocator(),
2609+
fixBehavior);
26092610
return failure.diagnose(asNote);
26102611
}
26112612

26122613
AllowConcreteTypeSpecialization *
26132614
AllowConcreteTypeSpecialization::create(ConstraintSystem &cs, Type concreteTy,
2614-
ConstraintLocator *locator) {
2615+
ConstraintLocator *locator,
2616+
FixBehavior fixBehavior) {
2617+
return new (cs.getAllocator())
2618+
AllowConcreteTypeSpecialization(cs, concreteTy, locator, fixBehavior);
2619+
}
2620+
2621+
bool AllowGenericFunctionSpecialization::diagnose(const Solution &solution,
2622+
bool asNote) const {
2623+
GenericFunctionSpecialization failure(solution, Decl, getLocator());
2624+
return failure.diagnose(asNote);
2625+
}
2626+
2627+
AllowGenericFunctionSpecialization *AllowGenericFunctionSpecialization::create(
2628+
ConstraintSystem &cs, ValueDecl *decl, ConstraintLocator *locator) {
26152629
return new (cs.getAllocator())
2616-
AllowConcreteTypeSpecialization(cs, concreteTy, locator);
2630+
AllowGenericFunctionSpecialization(cs, decl, locator);
26172631
}
26182632

26192633
bool IgnoreOutOfPlaceThenStmt::diagnose(const Solution &solution,

lib/Sema/CSGen.cpp

Lines changed: 26 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -1903,9 +1903,9 @@ namespace {
19031903
/// introduce them as an explicit generic arguments constraint.
19041904
///
19051905
/// \returns true if resolving any of the specialization types failed.
1906-
bool addSpecializationConstraint(
1907-
ConstraintLocator *locator, Type boundType,
1908-
ArrayRef<TypeRepr *> specializationArgs) {
1906+
void addSpecializationConstraint(ConstraintLocator *locator, Type boundType,
1907+
SourceLoc lAngleLoc,
1908+
ArrayRef<TypeRepr *> specializationArgs) {
19091909
// Resolve each type.
19101910
SmallVector<Type, 2> specializationArgTypes;
19111911
auto options =
@@ -1916,61 +1916,35 @@ namespace {
19161916
options |= TypeResolutionFlags::AllowPackReferences;
19171917
elementEnv = OuterExpansions.back();
19181918
}
1919-
const auto result = TypeResolution::resolveContextualType(
1919+
auto result = TypeResolution::resolveContextualType(
19201920
specializationArg, CurDC, options,
19211921
// Introduce type variables for unbound generics.
19221922
OpenUnboundGenericType(CS, locator),
19231923
HandlePlaceholderType(CS, locator),
19241924
OpenPackElementType(CS, locator, elementEnv));
1925-
if (result->hasError())
1926-
return true;
1927-
1925+
if (result->hasError()) {
1926+
auto &ctxt = CS.getASTContext();
1927+
result = PlaceholderType::get(ctxt, specializationArg);
1928+
ctxt.Diags.diagnose(lAngleLoc,
1929+
diag::while_parsing_as_left_angle_bracket);
1930+
}
19281931
specializationArgTypes.push_back(result);
19291932
}
19301933

1931-
CS.addConstraint(
1932-
ConstraintKind::ExplicitGenericArguments, boundType,
1933-
PackType::get(CS.getASTContext(), specializationArgTypes),
1934-
locator);
1935-
return false;
1934+
auto constraint = Constraint::create(
1935+
CS, ConstraintKind::ExplicitGenericArguments, boundType,
1936+
PackType::get(CS.getASTContext(), specializationArgTypes), locator);
1937+
CS.addUnsolvedConstraint(constraint);
1938+
CS.activateConstraint(constraint);
19361939
}
19371940

19381941
Type visitUnresolvedSpecializeExpr(UnresolvedSpecializeExpr *expr) {
19391942
auto baseTy = CS.getType(expr->getSubExpr());
1940-
1941-
if (baseTy->isTypeVariableOrMember()) {
1942-
return baseTy;
1943-
}
1944-
1945-
// We currently only support explicit specialization of generic types.
1946-
// FIXME: We could support explicit function specialization.
1947-
auto &de = CS.getASTContext().Diags;
1948-
if (baseTy->is<AnyFunctionType>()) {
1949-
de.diagnose(expr->getSubExpr()->getLoc(),
1950-
diag::cannot_explicitly_specialize_generic_function);
1951-
de.diagnose(expr->getLAngleLoc(),
1952-
diag::while_parsing_as_left_angle_bracket);
1953-
return Type();
1954-
}
1955-
1956-
if (AnyMetatypeType *meta = baseTy->getAs<AnyMetatypeType>()) {
1957-
auto *overloadLocator = CS.getConstraintLocator(expr->getSubExpr());
1958-
if (addSpecializationConstraint(overloadLocator,
1959-
meta->getInstanceType(),
1960-
expr->getUnresolvedParams())) {
1961-
return Type();
1962-
}
1963-
1964-
return baseTy;
1965-
}
1966-
1967-
// FIXME: If the base type is a type variable, constrain it to a metatype
1968-
// of a bound generic type.
1969-
de.diagnose(expr->getSubExpr()->getLoc(),
1970-
diag::not_a_generic_definition);
1971-
de.diagnose(expr->getLAngleLoc(),
1972-
diag::while_parsing_as_left_angle_bracket);
1973-
return Type();
1943+
auto *overloadLocator = CS.getConstraintLocator(expr->getSubExpr());
1944+
addSpecializationConstraint(
1945+
overloadLocator, baseTy->getMetatypeInstanceType(),
1946+
expr->getLAngleLoc(), expr->getUnresolvedParams());
1947+
return baseTy;
19741948
}
19751949

19761950
Type visitSequenceExpr(SequenceExpr *expr) {
@@ -4080,10 +4054,9 @@ namespace {
40804054

40814055
// Add explicit generic arguments, if there were any.
40824056
if (expr->getGenericArgsRange().isValid()) {
4083-
if (addSpecializationConstraint(
4084-
CS.getConstraintLocator(expr), macroRefType,
4085-
expr->getGenericArgs()))
4086-
return Type();
4057+
addSpecializationConstraint(CS.getConstraintLocator(expr), macroRefType,
4058+
expr->getGenericArgsRange().Start,
4059+
expr->getGenericArgs());
40874060
}
40884061

40894062
// Form the applicable-function constraint. The result type
@@ -4828,11 +4801,11 @@ bool ConstraintSystem::generateConstraints(
48284801
// If we have a placeholder originating from a PlaceholderTypeRepr,
48294802
// tack that on to the locator.
48304803
if (auto *placeholderTy = ty->getAs<PlaceholderType>())
4831-
if (auto *placeholderRepr = placeholderTy->getOriginator()
4832-
.dyn_cast<PlaceholderTypeRepr *>())
4804+
if (auto *typeRepr = placeholderTy->getOriginator()
4805+
.dyn_cast<TypeRepr *>())
48334806
return getConstraintLocator(
48344807
convertTypeLocator,
4835-
LocatorPathElt::PlaceholderType(placeholderRepr));
4808+
LocatorPathElt::PlaceholderType(typeRepr));
48364809
return convertTypeLocator;
48374810
};
48384811

0 commit comments

Comments
 (0)