Skip to content

Commit fdc7e25

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.
1 parent 6c9edfe commit fdc7e25

12 files changed

+164
-76
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/Sema/CSFix.h

Lines changed: 31 additions & 1 deletion
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

@@ -3743,6 +3746,33 @@ class AllowConcreteTypeSpecialization final : public ConstraintFix {
37433746
}
37443747
};
37453748

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

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: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9360,7 +9360,12 @@ bool InvalidMemberReferenceWithinInitAccessor::diagnoseAsError() {
93609360
}
93619361

93629362
bool ConcreteTypeSpecialization::diagnoseAsError() {
9363-
emitDiagnostic(diag::not_a_generic_type, ConcreteType);
9363+
emitDiagnostic(diag::not_a_generic_type, resolveType(ConcreteType));
9364+
return true;
9365+
}
9366+
9367+
bool GenericFunctionSpecialization::diagnoseAsError() {
9368+
emitDiagnostic(diag::cannot_explicitly_specialize_generic_function);
93649369
return true;
93659370
}
93669371

lib/Sema/CSDiagnostics.h

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3132,7 +3132,18 @@ class ConcreteTypeSpecialization final : public FailureDiagnostic {
31323132
ConcreteTypeSpecialization(const Solution &solution, Type concreteTy,
31333133
ConstraintLocator *locator)
31343134
: FailureDiagnostic(solution, locator),
3135-
ConcreteType(resolveType(concreteTy)) {}
3135+
ConcreteType(concreteTy) {}
3136+
3137+
bool diagnoseAsError() override;
3138+
};
3139+
3140+
class GenericFunctionSpecialization final : public FailureDiagnostic {
3141+
ValueDecl *Decl;
3142+
3143+
public:
3144+
GenericFunctionSpecialization(const Solution &solution, ValueDecl *decl,
3145+
ConstraintLocator *locator)
3146+
: FailureDiagnostic(solution, locator), Decl(decl) {}
31363147

31373148
bool diagnoseAsError() override;
31383149
};

lib/Sema/CSFix.cpp

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2616,6 +2616,18 @@ AllowConcreteTypeSpecialization::create(ConstraintSystem &cs, Type concreteTy,
26162616
AllowConcreteTypeSpecialization(cs, concreteTy, locator);
26172617
}
26182618

2619+
bool AllowGenericFunctionSpecialization::diagnose(const Solution &solution,
2620+
bool asNote) const {
2621+
GenericFunctionSpecialization failure(solution, Decl, getLocator());
2622+
return failure.diagnose(asNote);
2623+
}
2624+
2625+
AllowGenericFunctionSpecialization *AllowGenericFunctionSpecialization::create(
2626+
ConstraintSystem &cs, ValueDecl *decl, ConstraintLocator *locator) {
2627+
return new (cs.getAllocator())
2628+
AllowGenericFunctionSpecialization(cs, decl, locator);
2629+
}
2630+
26192631
bool IgnoreOutOfPlaceThenStmt::diagnose(const Solution &solution,
26202632
bool asNote) const {
26212633
OutOfPlaceThenStmtFailure failure(solution, getLocator());

lib/Sema/CSGen.cpp

Lines changed: 24 additions & 50 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,36 @@ 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+
auto *repr = new (ctxt) PlaceholderTypeRepr(specializationArg->getLoc());
1928+
result = PlaceholderType::get(ctxt, repr);
1929+
ctxt.Diags.diagnose(lAngleLoc,
1930+
diag::while_parsing_as_left_angle_bracket);
1931+
}
19281932
specializationArgTypes.push_back(result);
19291933
}
19301934

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

19381942
Type visitUnresolvedSpecializeExpr(UnresolvedSpecializeExpr *expr) {
19391943
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();
1944+
auto *overloadLocator = CS.getConstraintLocator(expr->getSubExpr());
1945+
addSpecializationConstraint(
1946+
overloadLocator, baseTy->getMetatypeInstanceType(),
1947+
expr->getLAngleLoc(), expr->getUnresolvedParams());
1948+
return baseTy;
19741949
}
19751950

19761951
Type visitSequenceExpr(SequenceExpr *expr) {
@@ -4080,10 +4055,9 @@ namespace {
40804055

40814056
// Add explicit generic arguments, if there were any.
40824057
if (expr->getGenericArgsRange().isValid()) {
4083-
if (addSpecializationConstraint(
4084-
CS.getConstraintLocator(expr), macroRefType,
4085-
expr->getGenericArgs()))
4086-
return Type();
4058+
addSpecializationConstraint(CS.getConstraintLocator(expr), macroRefType,
4059+
expr->getGenericArgsRange().Start,
4060+
expr->getGenericArgs());
40874061
}
40884062

40894063
// Form the applicable-function constraint. The result type

lib/Sema/CSSimplify.cpp

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -13950,6 +13950,8 @@ ConstraintSystem::simplifyExplicitGenericArgumentsConstraint(
1395013950

1395113951
// Bail out if we haven't selected an overload yet.
1395213952
auto simplifiedBoundType = simplifyType(type1, flags);
13953+
if (simplifiedBoundType->isPlaceholder())
13954+
return SolutionKind::Solved;
1395313955
if (simplifiedBoundType->isTypeVariableOrMember())
1395413956
return formUnsolved();
1395513957

@@ -14042,13 +14044,12 @@ ConstraintSystem::simplifyExplicitGenericArgumentsConstraint(
1404214044
}
1404314045
}
1404414046

14045-
if (!decl->getAsGenericContext())
14046-
return SolutionKind::Error;
14047-
1404814047
auto genericParams = getGenericParams(decl);
14049-
if (!genericParams) {
14050-
// FIXME: Record an error here that we're ignoring the parameters.
14051-
return SolutionKind::Solved;
14048+
if (!decl->getAsGenericContext() || !genericParams) {
14049+
return recordFix(AllowConcreteTypeSpecialization::create(
14050+
*this, type1, getConstraintLocator(locator)))
14051+
? SolutionKind::Error
14052+
: SolutionKind::Solved;
1405214053
}
1405314054

1405414055
// Map the generic parameters we have over to their opened types.
@@ -14081,12 +14082,14 @@ ConstraintSystem::simplifyExplicitGenericArgumentsConstraint(
1408114082
}
1408214083
}
1408314084

14084-
if (openedGenericParams.empty()) {
14085+
// FIXME: We could support explicit function specialization.
14086+
if (openedGenericParams.empty() ||
14087+
(isa<AbstractFunctionDecl>(decl) && !hasParameterPack)) {
1408514088
if (!shouldAttemptFixes())
1408614089
return SolutionKind::Error;
1408714090

14088-
return recordFix(AllowConcreteTypeSpecialization::create(
14089-
*this, type1, getConstraintLocator(locator)))
14091+
return recordFix(AllowGenericFunctionSpecialization::create(
14092+
*this, decl, getConstraintLocator(locator)))
1409014093
? SolutionKind::Error
1409114094
: SolutionKind::Solved;
1409214095
}
@@ -15217,6 +15220,7 @@ ConstraintSystem::SolutionKind ConstraintSystem::simplifyFixConstraint(
1521715220
case FixKind::AllowAssociatedValueMismatch:
1521815221
case FixKind::GenericArgumentsMismatch:
1521915222
case FixKind::AllowConcreteTypeSpecialization:
15223+
case FixKind::AllowGenericFunctionSpecialization:
1522015224
case FixKind::IgnoreGenericSpecializationArityMismatch:
1522115225
case FixKind::IgnoreKeyPathSubscriptIndexMismatch:
1522215226
case FixKind::AllowMemberRefOnExistential: {

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/enum_element_pattern_swift4.swift

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,13 @@ enum E {
99

1010
static func testE(e: E) {
1111
switch e {
12-
case A<UndefinedTy>(): // expected-error {{cannot specialize a non-generic definition}}
12+
case A<UndefinedTy>(): // expected-error {{cannot find type 'UndefinedTy' in scope}}
1313
// expected-note@-1 {{while parsing this '<' as a type parameter bracket}}
14+
// expected-error@-2 {{cannot specialize non-generic type 'E'}}
15+
// expected-error@-3 {{cannot call value of non-function type 'E'}}
1416
break
15-
case B<Int>(): // expected-error {{cannot specialize a non-generic definition}} expected-note {{while parsing this '<' as a type parameter bracket}}
17+
case B<Int>(): // expected-error {{cannot specialize non-generic type 'E'}}
18+
// expected-error@-1 {{cannot call value of non-function type 'E'}}
1619
break
1720
default:
1821
break;
@@ -22,10 +25,13 @@ enum E {
2225

2326
func testE(e: E) {
2427
switch e {
25-
case E.A<UndefinedTy>(): // expected-error {{cannot specialize a non-generic definition}}
28+
case E.A<UndefinedTy>(): // expected-error {{cannot find type 'UndefinedTy' in scope}}
2629
// expected-note@-1 {{while parsing this '<' as a type parameter bracket}}
30+
// expected-error@-2 {{cannot specialize non-generic type 'E'}}
31+
// expected-error@-3 {{cannot call value of non-function type 'E'}}
2732
break
28-
case E.B<Int>(): // expected-error {{cannot specialize a non-generic definition}} expected-note {{while parsing this '<' as a type parameter bracket}}
33+
case E.B<Int>(): // expected-error {{cannot specialize non-generic type 'E'}}
34+
// expected-error@-1 {{cannot call value of non-function type 'E'}}
2935
break
3036
case .C(): // expected-error {{pattern with associated values does not match enum case 'C'}}
3137
// expected-note@-1 {{remove associated values to make the pattern match}} {{10-12=}}

test/Parse/generic_disambiguation.swift

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -26,15 +26,21 @@ var a, b, c, d : Int
2626
_ = a < b
2727
_ = (a < b, c > d)
2828
// Parses as generic because of lparen after '>'
29-
(a < b, c > (d)) // expected-error{{cannot specialize a non-generic definition}}
30-
// expected-note@-1 {{while parsing this '<' as a type parameter bracket}}
29+
(a < b, c > (d)) // expected-error{{cannot find type 'b' in scope}}
30+
// expected-note@-1 2 {{while parsing this '<' as a type parameter bracket}}
31+
// expected-error@-2 {{cannot specialize non-generic type 'Int'}}
32+
// expected-error@-3 {{cannot call value of non-function type 'Int'}}
33+
// expected-error@-4 {{cannot find type 'c' in scope}}
3134
// Parses as generic because of lparen after '>'
32-
(a<b, c>(d)) // expected-error{{cannot specialize a non-generic definition}}
33-
// expected-note@-1 {{while parsing this '<' as a type parameter bracket}}
35+
(a<b, c>(d)) // expected-error{{cannot find type 'b' in scope}}
36+
// expected-note@-1 2 {{while parsing this '<' as a type parameter bracket}}
37+
// expected-error@-2 {{cannot specialize non-generic type 'Int'}}
38+
// expected-error@-3 {{cannot call value of non-function type 'Int'}}
39+
// expected-error@-4 {{cannot find type 'c' in scope}}
3440
_ = a>(b)
3541
_ = a > (b)
3642

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

3945
A<B>.c()
4046
A<A<B>>.c()

test/Sema/generic-arg-list.swift

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
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 2 {{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+
let _ = i.gen<Int> // expected-error {{cannot explicitly specialize a generic function}}
25+
// expected-error@-1 {{generic parameter 'T' could not be inferred}}
26+
let _ = i.bar<Int> // expected-error {{cannot specialize non-generic type 'Int'}}
27+
let _ = 0.bar<Int> // expected-error {{cannot specialize non-generic type 'Int'}}
28+
}
29+
30+
extension Bool {
31+
func foo<T>() -> T {}
32+
}
33+
34+
let _: () -> Bool = false.foo<Int> // expected-error {{cannot explicitly specialize a generic function}}
35+
36+
func foo(_ x: Int) {
37+
_ = {
38+
_ = x<String> // expected-error {{cannot specialize non-generic type 'Int'}}
39+
}
40+
}
41+

0 commit comments

Comments
 (0)