Skip to content

Commit 47acc09

Browse files
authored
Merge pull request #74909 from gregomni/generic-arg
[Sema] Add specialization constraints for func and variable types, then diagnose w/fixes.
2 parents dfeb52b + 6e917b5 commit 47acc09

12 files changed

+164
-76
lines changed

Diff for: include/swift/AST/DiagnosticsSema.def

-2
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,

Diff for: include/swift/Sema/CSFix.h

+31-1
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) {}

Diff for: lib/Parse/ParseType.cpp

+3-1
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:

Diff for: lib/Sema/CSDiagnostics.cpp

+6-1
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

Diff for: lib/Sema/CSDiagnostics.h

+12-1
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
};

Diff for: lib/Sema/CSFix.cpp

+12
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());

Diff for: lib/Sema/CSGen.cpp

+24-50
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

Diff for: lib/Sema/CSSimplify.cpp

+13-9
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: {

Diff for: test/Constraints/ambiguous_specialized_name_diagnostics.swift

+1-2
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
}

Diff for: test/Parse/enum_element_pattern_swift4.swift

+10-4
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=}}

Diff for: test/Parse/generic_disambiguation.swift

+11-5
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()

Diff for: test/Sema/generic-arg-list.swift

+41
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)