Skip to content

Commit 4d21511

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 0350023 commit 4d21511

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
@@ -4628,8 +4628,6 @@ NOTE(duplicated_key_declared_here, none,
46284628
// Generic specializations
46294629
ERROR(cannot_explicitly_specialize_generic_function,none,
46304630
"cannot explicitly specialize a generic function", ())
4631-
ERROR(not_a_generic_definition,none,
4632-
"cannot specialize a non-generic definition", ())
46334631
ERROR(not_a_generic_type,none,
46344632
"cannot specialize non-generic type %0", (Type))
46354633
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
@@ -459,9 +459,12 @@ 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 non-generic type.
463463
AllowConcreteTypeSpecialization,
464464

465+
/// Ignore an attempt to specialize a generic function.
466+
AllowGenericFunctionSpecialization,
467+
465468
/// Ignore an out-of-place \c then statement.
466469
IgnoreOutOfPlaceThenStmt,
467470

@@ -3713,6 +3716,33 @@ class AllowConcreteTypeSpecialization final : public ConstraintFix {
37133716
}
37143717
};
37153718

3719+
class AllowGenericFunctionSpecialization final : public ConstraintFix {
3720+
ValueDecl *Decl;
3721+
3722+
AllowGenericFunctionSpecialization(ConstraintSystem &cs, ValueDecl *decl,
3723+
ConstraintLocator *locator)
3724+
: ConstraintFix(cs, FixKind::AllowConcreteTypeSpecialization, locator),
3725+
Decl(decl) {}
3726+
3727+
public:
3728+
std::string getName() const override {
3729+
return "allow generic function specialization";
3730+
}
3731+
3732+
bool diagnose(const Solution &solution, bool asNote = false) const override;
3733+
3734+
bool diagnoseForAmbiguity(CommonFixesArray commonFixes) const override {
3735+
return diagnose(*commonFixes.front().first);
3736+
}
3737+
3738+
static AllowGenericFunctionSpecialization *
3739+
create(ConstraintSystem &cs, ValueDecl *decl, ConstraintLocator *locator);
3740+
3741+
static bool classof(const ConstraintFix *fix) {
3742+
return fix->getKind() == FixKind::AllowGenericFunctionSpecialization;
3743+
}
3744+
};
3745+
37163746
class IgnoreOutOfPlaceThenStmt final : public ConstraintFix {
37173747
IgnoreOutOfPlaceThenStmt(ConstraintSystem &cs, ConstraintLocator *locator)
37183748
: ConstraintFix(cs, FixKind::IgnoreOutOfPlaceThenStmt, locator) {}

lib/Parse/ParseType.cpp

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

lib/Sema/CSDiagnostics.cpp

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9338,7 +9338,12 @@ bool InvalidMemberReferenceWithinInitAccessor::diagnoseAsError() {
93389338
}
93399339

93409340
bool ConcreteTypeSpecialization::diagnoseAsError() {
9341-
emitDiagnostic(diag::not_a_generic_type, ConcreteType);
9341+
emitDiagnostic(diag::not_a_generic_type, resolveType(ConcreteType));
9342+
return true;
9343+
}
9344+
9345+
bool GenericFunctionSpecialization::diagnoseAsError() {
9346+
emitDiagnostic(diag::cannot_explicitly_specialize_generic_function);
93429347
return true;
93439348
}
93449349

lib/Sema/CSDiagnostics.h

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3116,7 +3116,18 @@ class ConcreteTypeSpecialization final : public FailureDiagnostic {
31163116
ConcreteTypeSpecialization(const Solution &solution, Type concreteTy,
31173117
ConstraintLocator *locator)
31183118
: FailureDiagnostic(solution, locator),
3119-
ConcreteType(resolveType(concreteTy)) {}
3119+
ConcreteType(concreteTy) {}
3120+
3121+
bool diagnoseAsError() override;
3122+
};
3123+
3124+
class GenericFunctionSpecialization final : public FailureDiagnostic {
3125+
ValueDecl *Decl;
3126+
3127+
public:
3128+
GenericFunctionSpecialization(const Solution &solution, ValueDecl *decl,
3129+
ConstraintLocator *locator)
3130+
: FailureDiagnostic(solution, locator), Decl(decl) {}
31203131

31213132
bool diagnoseAsError() override;
31223133
};

lib/Sema/CSFix.cpp

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2604,6 +2604,18 @@ AllowConcreteTypeSpecialization::create(ConstraintSystem &cs, Type concreteTy,
26042604
AllowConcreteTypeSpecialization(cs, concreteTy, locator);
26052605
}
26062606

2607+
bool AllowGenericFunctionSpecialization::diagnose(const Solution &solution,
2608+
bool asNote) const {
2609+
GenericFunctionSpecialization failure(solution, Decl, getLocator());
2610+
return failure.diagnose(asNote);
2611+
}
2612+
2613+
AllowGenericFunctionSpecialization *AllowGenericFunctionSpecialization::create(
2614+
ConstraintSystem &cs, ValueDecl *decl, ConstraintLocator *locator) {
2615+
return new (cs.getAllocator())
2616+
AllowGenericFunctionSpecialization(cs, decl, locator);
2617+
}
2618+
26072619
bool IgnoreOutOfPlaceThenStmt::diagnose(const Solution &solution,
26082620
bool asNote) const {
26092621
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) {
@@ -4082,10 +4057,9 @@ namespace {
40824057

40834058
// Add explicit generic arguments, if there were any.
40844059
if (expr->getGenericArgsRange().isValid()) {
4085-
if (addSpecializationConstraint(
4086-
CS.getConstraintLocator(expr), macroRefType,
4087-
expr->getGenericArgs()))
4088-
return Type();
4060+
addSpecializationConstraint(CS.getConstraintLocator(expr), macroRefType,
4061+
expr->getGenericArgsRange().Start,
4062+
expr->getGenericArgs());
40894063
}
40904064

40914065
// 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
@@ -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, 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

14064-
return recordFix(AllowConcreteTypeSpecialization::create(
14065-
*this, type1, getConstraintLocator(locator)))
14067+
return recordFix(AllowGenericFunctionSpecialization::create(
14068+
*this, decl, getConstraintLocator(locator)))
1406614069
? SolutionKind::Error
1406714070
: SolutionKind::Solved;
1406814071
}
@@ -15193,6 +15196,7 @@ ConstraintSystem::SolutionKind ConstraintSystem::simplifyFixConstraint(
1519315196
case FixKind::AllowAssociatedValueMismatch:
1519415197
case FixKind::GenericArgumentsMismatch:
1519515198
case FixKind::AllowConcreteTypeSpecialization:
15199+
case FixKind::AllowGenericFunctionSpecialization:
1519615200
case FixKind::IgnoreGenericSpecializationArityMismatch:
1519715201
case FixKind::IgnoreKeyPathSubscriptIndexMismatch:
1519815202
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)