Skip to content

Commit ce7cb0a

Browse files
author
Greg Titus
committed
Add specialization constraints for func types and variables and diagnose with fixes.
1 parent 0350023 commit ce7cb0a

File tree

10 files changed

+91
-46
lines changed

10 files changed

+91
-46
lines changed

include/swift/Sema/CSFix.h

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -459,7 +459,7 @@ enum class FixKind : uint8_t {
459459
/// because its name doesn't appear in 'initializes' or 'accesses' attributes.
460460
AllowInvalidMemberReferenceInInitAccessor,
461461

462-
/// Ignore an attempt to specialize non-generic type.
462+
/// Ignore an attempt to specialize a generic function or non-generic type.
463463
AllowConcreteTypeSpecialization,
464464

465465
/// Ignore an out-of-place \c then statement.
@@ -3688,11 +3688,12 @@ class AllowInvalidMemberReferenceInInitAccessor final : public ConstraintFix {
36883688

36893689
class AllowConcreteTypeSpecialization final : public ConstraintFix {
36903690
Type ConcreteType;
3691+
ValueDecl *Decl;
36913692

36923693
AllowConcreteTypeSpecialization(ConstraintSystem &cs, Type concreteTy,
3693-
ConstraintLocator *locator)
3694+
ValueDecl *decl, ConstraintLocator *locator)
36943695
: ConstraintFix(cs, FixKind::AllowConcreteTypeSpecialization, locator),
3695-
ConcreteType(concreteTy) {}
3696+
ConcreteType(concreteTy), Decl(decl) {}
36963697

36973698
public:
36983699
std::string getName() const override {
@@ -3705,8 +3706,10 @@ class AllowConcreteTypeSpecialization final : public ConstraintFix {
37053706
return diagnose(*commonFixes.front().first);
37063707
}
37073708

3708-
static AllowConcreteTypeSpecialization *
3709-
create(ConstraintSystem &cs, Type concreteTy, ConstraintLocator *locator);
3709+
static AllowConcreteTypeSpecialization *create(ConstraintSystem &cs,
3710+
Type concreteTy,
3711+
ValueDecl *decl,
3712+
ConstraintLocator *locator);
37103713

37113714
static bool classof(const ConstraintFix *fix) {
37123715
return fix->getKind() == FixKind::AllowConcreteTypeSpecialization;

lib/Sema/CSApply.cpp

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3225,7 +3225,6 @@ namespace {
32253225
}
32263226

32273227
Expr *visitUnresolvedSpecializeExpr(UnresolvedSpecializeExpr *expr) {
3228-
// Our specializations should have resolved the subexpr to the right type.
32293228
return expr->getSubExpr();
32303229
}
32313230

lib/Sema/CSDiagnostics.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6602,6 +6602,7 @@ bool MissingGenericArgumentsFailure::diagnoseForAnchor(
66026602
bool MissingGenericArgumentsFailure::diagnoseParameter(
66036603
ASTNode anchor, GenericTypeParamType *GP) const {
66046604
auto &solution = getSolution();
6605+
auto &CS = solution.getConstraintSystem();
66056606
auto loc = ::getLoc(anchor);
66066607

66076608
auto *locator = getLocator();
@@ -9338,6 +9339,13 @@ bool InvalidMemberReferenceWithinInitAccessor::diagnoseAsError() {
93389339
}
93399340

93409341
bool ConcreteTypeSpecialization::diagnoseAsError() {
9342+
if (isa<AbstractFunctionDecl>(Decl)) {
9343+
auto genericContext = Decl->getAsGenericContext();
9344+
if (genericContext && genericContext->getGenericParams()) {
9345+
emitDiagnostic(diag::cannot_explicitly_specialize_generic_function);
9346+
return true;
9347+
}
9348+
}
93419349
emitDiagnostic(diag::not_a_generic_type, ConcreteType);
93429350
return true;
93439351
}

lib/Sema/CSDiagnostics.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3111,12 +3111,13 @@ class InvalidMemberReferenceWithinInitAccessor final
31113111
/// \endcode
31123112
class ConcreteTypeSpecialization final : public FailureDiagnostic {
31133113
Type ConcreteType;
3114+
ValueDecl *Decl;
31143115

31153116
public:
31163117
ConcreteTypeSpecialization(const Solution &solution, Type concreteTy,
3117-
ConstraintLocator *locator)
3118+
ValueDecl *decl, ConstraintLocator *locator)
31183119
: FailureDiagnostic(solution, locator),
3119-
ConcreteType(resolveType(concreteTy)) {}
3120+
ConcreteType(resolveType(concreteTy)), Decl(decl) {}
31203121

31213122
bool diagnoseAsError() override;
31223123
};

lib/Sema/CSFix.cpp

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2593,15 +2593,17 @@ AllowInvalidMemberReferenceInInitAccessor::create(ConstraintSystem &cs,
25932593

25942594
bool AllowConcreteTypeSpecialization::diagnose(const Solution &solution,
25952595
bool asNote) const {
2596-
ConcreteTypeSpecialization failure(solution, ConcreteType, getLocator());
2596+
ConcreteTypeSpecialization failure(solution, ConcreteType, Decl,
2597+
getLocator());
25972598
return failure.diagnose(asNote);
25982599
}
25992600

26002601
AllowConcreteTypeSpecialization *
26012602
AllowConcreteTypeSpecialization::create(ConstraintSystem &cs, Type concreteTy,
2603+
ValueDecl *decl,
26022604
ConstraintLocator *locator) {
26032605
return new (cs.getAllocator())
2604-
AllowConcreteTypeSpecialization(cs, concreteTy, locator);
2606+
AllowConcreteTypeSpecialization(cs, concreteTy, decl, locator);
26052607
}
26062608

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

lib/Sema/CSGen.cpp

Lines changed: 15 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1937,40 +1937,30 @@ namespace {
19371937

19381938
Type visitUnresolvedSpecializeExpr(UnresolvedSpecializeExpr *expr) {
19391939
auto baseTy = CS.getType(expr->getSubExpr());
1940+
Type specializeTy = nullptr;
19401941

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>()) {
1942+
if (baseTy->isTypeVariableOrMember() || baseTy->is<AnyFunctionType>()) {
1943+
specializeTy = baseTy;
1944+
} else if (AnyMetatypeType *meta = baseTy->getAs<AnyMetatypeType>()) {
1945+
specializeTy = meta->getInstanceType();
1946+
} else {
1947+
// FIXME: If the base type is a type variable, constrain it to a
1948+
// metatype of a bound generic type.
1949+
auto &de = CS.getASTContext().Diags;
19491950
de.diagnose(expr->getSubExpr()->getLoc(),
1950-
diag::cannot_explicitly_specialize_generic_function);
1951+
diag::not_a_generic_definition);
19511952
de.diagnose(expr->getLAngleLoc(),
19521953
diag::while_parsing_as_left_angle_bracket);
19531954
return Type();
19541955
}
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-
}
19631956

1964-
return baseTy;
1957+
auto *overloadLocator = CS.getConstraintLocator(expr->getSubExpr());
1958+
if (addSpecializationConstraint(overloadLocator, specializeTy,
1959+
expr->getUnresolvedParams())) {
1960+
return Type();
19651961
}
19661962

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();
1963+
return baseTy;
19741964
}
19751965

19761966
Type visitSequenceExpr(SequenceExpr *expr) {

lib/Sema/CSSimplify.cpp

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -13926,6 +13926,8 @@ ConstraintSystem::simplifyExplicitGenericArgumentsConstraint(
1392613926

1392713927
// Bail out if we haven't selected an overload yet.
1392813928
auto simplifiedBoundType = simplifyType(type1, flags);
13929+
if (simplifiedBoundType->isPlaceholder())
13930+
return SolutionKind::Solved;
1392913931
if (simplifiedBoundType->isTypeVariableOrMember())
1393013932
return formUnsolved();
1393113933

@@ -14018,13 +14020,12 @@ ConstraintSystem::simplifyExplicitGenericArgumentsConstraint(
1401814020
}
1401914021
}
1402014022

14021-
if (!decl->getAsGenericContext())
14022-
return SolutionKind::Error;
14023-
1402414023
auto genericParams = getGenericParams(decl);
14025-
if (!genericParams) {
14026-
// FIXME: Record an error here that we're ignoring the parameters.
14027-
return SolutionKind::Solved;
14024+
if (!decl->getAsGenericContext() || !genericParams) {
14025+
return recordFix(AllowConcreteTypeSpecialization::create(
14026+
*this, type1, decl, getConstraintLocator(locator)))
14027+
? SolutionKind::Error
14028+
: SolutionKind::Solved;
1402814029
}
1402914030

1403014031
// Map the generic parameters we have over to their opened types.
@@ -14057,12 +14058,14 @@ ConstraintSystem::simplifyExplicitGenericArgumentsConstraint(
1405714058
}
1405814059
}
1405914060

14060-
if (openedGenericParams.empty()) {
14061+
// FIXME: We could support explicit function specialization.
14062+
if (openedGenericParams.empty() ||
14063+
(isa<AbstractFunctionDecl>(decl) && !hasParameterPack)) {
1406114064
if (!shouldAttemptFixes())
1406214065
return SolutionKind::Error;
1406314066

1406414067
return recordFix(AllowConcreteTypeSpecialization::create(
14065-
*this, type1, getConstraintLocator(locator)))
14068+
*this, type1, decl, getConstraintLocator(locator)))
1406614069
? SolutionKind::Error
1406714070
: SolutionKind::Solved;
1406814071
}

test/Constraints/ambiguous_specialized_name_diagnostics.swift

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,6 @@ func test() {
4242

4343
S<Int>(t: 42).test() // expected-error {{ambiguous use of 'init(t:)'}}
4444

45-
// FIXME(diagnostics): This should produce ambiguity diagnostic too
4645
S<Int>.staticFn()
47-
// expected-error@-1 {{generic parameter 'T' could not be inferred}}
46+
// expected-error@-1 {{ambiguous use of 'staticFn()'}}
4847
}

test/Parse/generic_disambiguation.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ _ = (a < b, c > d)
3434
_ = a>(b)
3535
_ = a > (b)
3636

37-
generic<Int>(0) // expected-error{{cannot explicitly specialize a generic function}} expected-note{{while parsing this '<' as a type parameter bracket}}
37+
generic<Int>(0) // expected-error{{cannot explicitly specialize a generic function}}
3838

3939
A<B>.c()
4040
A<A<B>>.c()

test/Sema/generic-arg-list.swift

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
// RUN: %target-typecheck-verify-swift
2+
3+
extension Int {
4+
func foo() -> Int {}
5+
var bar: Int {
6+
get {}
7+
}
8+
9+
func baz() -> Int {}
10+
func baz(_ x: Int = 0) -> Int {}
11+
12+
func gen<T>() -> T {} // expected-note {{in call to function 'gen()'}}
13+
}
14+
15+
// https://github.com/swiftlang/swift/issues/74857
16+
func test(i: Int) {
17+
let _ = i.foo<Int>() // expected-error {{cannot specialize non-generic type '() -> Int'}}
18+
19+
let _ = i.gen<Int>() // expected-error {{cannot explicitly specialize a generic function}}
20+
// expected-error@-1 {{generic parameter 'T' could not be inferred}}
21+
22+
let _ = 0.foo<Int>() // expected-error {{cannot specialize non-generic type '() -> Int'}}
23+
24+
// FIXME: These get parsed as postfix >, unless at the end of a block
25+
let _ = i.gen<Int> // expected-error {{'>' is not a postfix unary operator}}
26+
// expected-error@-1 {{binary operator '<' cannot be applied to operands of type '() -> ()' and '()'}}
27+
// expected-note@-2 {{overloads for '<' exist with these partially matching parameter lists: ((), ()), (AnyIndex, AnyIndex), (Character, Character), (Int, Int), (Int16, Int16), (Int32, Int32), (Int64, Int64), (Int8, Int8), (Never, Never), (ObjectIdentifier, ObjectIdentifier), (String, String), (String.Index, String.Index), (UInt, UInt), (UInt16, UInt16), (UInt32, UInt32), (UInt64, UInt64), (UInt8, UInt8), (Unicode.CanonicalCombiningClass, Unicode.CanonicalCombiningClass), (Unicode.Scalar, Unicode.Scalar), (_ValidUTF8Buffer.Index, _ValidUTF8Buffer.Index)}}
28+
let _ = i.baz<Int> // expected-error {{'>' is not a postfix unary operator}}
29+
// expected-error@-1 {{function produces expected type 'Int'; did you mean to call it with '()'?}}
30+
let _ = i.bar<Int> // expected-error {{'>' is not a postfix unary operator}}
31+
32+
let _ = 0.bar<Int> // expected-error {{cannot specialize non-generic type 'Int'}}
33+
}
34+
35+
extension Bool {
36+
func foo<T>() -> T {}
37+
}
38+
39+
let _: () -> Bool = false.foo<Int> // expected-error {{cannot explicitly specialize a generic function}}
40+

0 commit comments

Comments
 (0)