Skip to content

Commit ceeb6ec

Browse files
authored
Merge pull request #75526 from gregomni/specialize
[Sema] Improve diagnoses of generic specializations
2 parents 4ce62af + d87e049 commit ceeb6ec

19 files changed

+218
-110
lines changed

include/swift/AST/DiagnosticsSema.def

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4605,10 +4605,10 @@ 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))
4610+
ERROR(not_a_generic_macro,none,
4611+
"cannot specialize a non-generic external macro %0", (const ValueDecl *))
46124612
ERROR(protocol_declares_unknown_primary_assoc_type,none,
46134613
"an associated type named %0 must be declared in the protocol %1 or a protocol it inherits",
46144614
(Identifier, Type))

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

@@ -3718,11 +3721,14 @@ class AllowInvalidMemberReferenceInInitAccessor final : public ConstraintFix {
37183721

37193722
class AllowConcreteTypeSpecialization final : public ConstraintFix {
37203723
Type ConcreteType;
3724+
ValueDecl *Decl;
37213725

37223726
AllowConcreteTypeSpecialization(ConstraintSystem &cs, Type concreteTy,
3723-
ConstraintLocator *locator)
3724-
: ConstraintFix(cs, FixKind::AllowConcreteTypeSpecialization, locator),
3725-
ConcreteType(concreteTy) {}
3727+
ValueDecl *decl, ConstraintLocator *locator,
3728+
FixBehavior fixBehavior)
3729+
: ConstraintFix(cs, FixKind::AllowConcreteTypeSpecialization, locator,
3730+
fixBehavior),
3731+
ConcreteType(concreteTy), Decl(decl) {}
37263732

37273733
public:
37283734
std::string getName() const override {
@@ -3736,13 +3742,41 @@ class AllowConcreteTypeSpecialization final : public ConstraintFix {
37363742
}
37373743

37383744
static AllowConcreteTypeSpecialization *
3739-
create(ConstraintSystem &cs, Type concreteTy, ConstraintLocator *locator);
3745+
create(ConstraintSystem &cs, Type concreteTy, ValueDecl *decl,
3746+
ConstraintLocator *locator, 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 & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9360,7 +9360,16 @@ bool InvalidMemberReferenceWithinInitAccessor::diagnoseAsError() {
93609360
}
93619361

93629362
bool ConcreteTypeSpecialization::diagnoseAsError() {
9363-
emitDiagnostic(diag::not_a_generic_type, ConcreteType);
9363+
if (isa<MacroDecl>(Decl)) {
9364+
emitDiagnostic(diag::not_a_generic_macro, Decl);
9365+
} else {
9366+
emitDiagnostic(diag::not_a_generic_type, ConcreteType);
9367+
}
9368+
return true;
9369+
}
9370+
9371+
bool GenericFunctionSpecialization::diagnoseAsError() {
9372+
emitDiagnostic(diag::cannot_explicitly_specialize_generic_function);
93649373
return true;
93659374
}
93669375

lib/Sema/CSDiagnostics.h

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3127,12 +3127,25 @@ class InvalidMemberReferenceWithinInitAccessor final
31273127
/// \endcode
31283128
class ConcreteTypeSpecialization final : public FailureDiagnostic {
31293129
Type ConcreteType;
3130+
ValueDecl *Decl;
31303131

31313132
public:
31323133
ConcreteTypeSpecialization(const Solution &solution, Type concreteTy,
3133-
ConstraintLocator *locator)
3134-
: FailureDiagnostic(solution, locator),
3135-
ConcreteType(resolveType(concreteTy)) {}
3134+
ValueDecl *decl, ConstraintLocator *locator,
3135+
FixBehavior fixBehavior)
3136+
: FailureDiagnostic(solution, locator, fixBehavior),
3137+
ConcreteType(resolveType(concreteTy)), Decl(decl) {}
3138+
3139+
bool diagnoseAsError() override;
3140+
};
3141+
3142+
class GenericFunctionSpecialization final : public FailureDiagnostic {
3143+
ValueDecl *Decl;
3144+
3145+
public:
3146+
GenericFunctionSpecialization(const Solution &solution, ValueDecl *decl,
3147+
ConstraintLocator *locator)
3148+
: FailureDiagnostic(solution, locator), Decl(decl) {}
31363149

31373150
bool diagnoseAsError() override;
31383151
};

lib/Sema/CSFix.cpp

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2605,15 +2605,28 @@ 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, Decl, getLocator(),
2609+
fixBehavior);
26092610
return failure.diagnose(asNote);
26102611
}
26112612

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

26192632
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)