Skip to content

Commit fab7628

Browse files
authored
Merge pull request #67026 from xedin/fix-specialization-issues-5.9
[5.9][ConstraintSystem] Fix a couple of issues related to generic specialization
2 parents d82ed63 + 7d05a58 commit fab7628

File tree

7 files changed

+261
-9
lines changed

7 files changed

+261
-9
lines changed

include/swift/Sema/CSFix.h

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -454,6 +454,13 @@ enum class FixKind : uint8_t {
454454
/// Ignore the fact that member couldn't be referenced within init accessor
455455
/// because its name doesn't appear in 'initializes' or 'accesses' attributes.
456456
AllowInvalidMemberReferenceInInitAccessor,
457+
458+
/// Ignore an attempt to specialize non-generic type.
459+
AllowConcreteTypeSpecialization,
460+
461+
/// Ignore situations when provided number of generic arguments didn't match
462+
/// expected number of parameters.
463+
IgnoreGenericSpecializationArityMismatch,
457464
};
458465

459466
class ConstraintFix {
@@ -3647,6 +3654,69 @@ class AllowInvalidMemberReferenceInInitAccessor final : public ConstraintFix {
36473654
}
36483655
};
36493656

3657+
class AllowConcreteTypeSpecialization final : public ConstraintFix {
3658+
Type ConcreteType;
3659+
3660+
AllowConcreteTypeSpecialization(ConstraintSystem &cs, Type concreteTy,
3661+
ConstraintLocator *locator)
3662+
: ConstraintFix(cs, FixKind::AllowConcreteTypeSpecialization, locator),
3663+
ConcreteType(concreteTy) {}
3664+
3665+
public:
3666+
std::string getName() const override {
3667+
return "allow concrete type specialization";
3668+
}
3669+
3670+
bool diagnose(const Solution &solution, bool asNote = false) const override;
3671+
3672+
bool diagnoseForAmbiguity(CommonFixesArray commonFixes) const override {
3673+
return diagnose(*commonFixes.front().first);
3674+
}
3675+
3676+
static AllowConcreteTypeSpecialization *
3677+
create(ConstraintSystem &cs, Type concreteTy, ConstraintLocator *locator);
3678+
3679+
static bool classof(const ConstraintFix *fix) {
3680+
return fix->getKind() == FixKind::AllowConcreteTypeSpecialization;
3681+
}
3682+
};
3683+
3684+
class IgnoreGenericSpecializationArityMismatch final : public ConstraintFix {
3685+
ValueDecl *D;
3686+
unsigned NumParams;
3687+
unsigned NumArgs;
3688+
bool HasParameterPack;
3689+
3690+
IgnoreGenericSpecializationArityMismatch(ConstraintSystem &cs,
3691+
ValueDecl *decl, unsigned numParams,
3692+
unsigned numArgs,
3693+
bool hasParameterPack,
3694+
ConstraintLocator *locator)
3695+
: ConstraintFix(cs, FixKind::IgnoreGenericSpecializationArityMismatch,
3696+
locator),
3697+
D(decl), NumParams(numParams), NumArgs(numArgs),
3698+
HasParameterPack(hasParameterPack) {}
3699+
3700+
public:
3701+
std::string getName() const override {
3702+
return "ignore generic specialization mismatch";
3703+
}
3704+
3705+
bool diagnose(const Solution &solution, bool asNote = false) const override;
3706+
3707+
bool diagnoseForAmbiguity(CommonFixesArray commonFixes) const override {
3708+
return diagnose(*commonFixes.front().first);
3709+
}
3710+
3711+
static IgnoreGenericSpecializationArityMismatch *
3712+
create(ConstraintSystem &cs, ValueDecl *decl, unsigned numParams,
3713+
unsigned numArgs, bool hasParameterPack, ConstraintLocator *locator);
3714+
3715+
static bool classof(const ConstraintFix *fix) {
3716+
return fix->getKind() == FixKind::IgnoreGenericSpecializationArityMismatch;
3717+
}
3718+
};
3719+
36503720
} // end namespace constraints
36513721
} // end namespace swift
36523722

lib/Sema/CSDiagnostics.cpp

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9101,3 +9101,14 @@ bool InvalidMemberReferenceWithinInitAccessor::diagnoseAsError() {
91019101
emitDiagnostic(diag::init_accessor_invalid_member_ref, MemberName);
91029102
return true;
91039103
}
9104+
9105+
bool ConcreteTypeSpecialization::diagnoseAsError() {
9106+
emitDiagnostic(diag::not_a_generic_type, ConcreteType);
9107+
return true;
9108+
}
9109+
9110+
bool InvalidTypeSpecializationArity::diagnoseAsError() {
9111+
emitDiagnostic(diag::type_parameter_count_mismatch, D->getBaseIdentifier(),
9112+
NumParams, NumArgs, NumArgs < NumParams, HasParameterPack);
9113+
return true;
9114+
}

lib/Sema/CSDiagnostics.h

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3036,6 +3036,50 @@ class InvalidMemberReferenceWithinInitAccessor final
30363036
bool diagnoseAsError() override;
30373037
};
30383038

3039+
/// Diagnose attempts to specialize a concrete type or its alias:
3040+
///
3041+
/// \code
3042+
/// struct Test {}
3043+
/// typealias X = Test
3044+
///
3045+
/// _ = X<Int>() // error
3046+
/// \endcode
3047+
class ConcreteTypeSpecialization final : public FailureDiagnostic {
3048+
Type ConcreteType;
3049+
3050+
public:
3051+
ConcreteTypeSpecialization(const Solution &solution, Type concreteTy,
3052+
ConstraintLocator *locator)
3053+
: FailureDiagnostic(solution, locator),
3054+
ConcreteType(resolveType(concreteTy)) {}
3055+
3056+
bool diagnoseAsError() override;
3057+
};
3058+
3059+
/// Diagnose attempts to specialize with invalid number of generic arguments:
3060+
///
3061+
/// \code
3062+
/// struct Test<T, U> {}
3063+
///
3064+
/// _ = Test<Int>() // error
3065+
/// \endcode
3066+
class InvalidTypeSpecializationArity final : public FailureDiagnostic {
3067+
ValueDecl *D;
3068+
unsigned NumParams;
3069+
unsigned NumArgs;
3070+
bool HasParameterPack;
3071+
3072+
public:
3073+
InvalidTypeSpecializationArity(const Solution &solution, ValueDecl *decl,
3074+
unsigned numParams, unsigned numArgs,
3075+
bool hasParameterPack,
3076+
ConstraintLocator *locator)
3077+
: FailureDiagnostic(solution, locator), D(decl), NumParams(numParams),
3078+
NumArgs(numArgs), HasParameterPack(hasParameterPack) {}
3079+
3080+
bool diagnoseAsError() override;
3081+
};
3082+
30393083
} // end namespace constraints
30403084
} // end namespace swift
30413085

lib/Sema/CSFix.cpp

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2837,3 +2837,34 @@ AllowInvalidMemberReferenceInInitAccessor::create(ConstraintSystem &cs,
28372837
return new (cs.getAllocator())
28382838
AllowInvalidMemberReferenceInInitAccessor(cs, memberName, locator);
28392839
}
2840+
2841+
bool AllowConcreteTypeSpecialization::diagnose(const Solution &solution,
2842+
bool asNote) const {
2843+
ConcreteTypeSpecialization failure(solution, ConcreteType, getLocator());
2844+
return failure.diagnose(asNote);
2845+
}
2846+
2847+
AllowConcreteTypeSpecialization *
2848+
AllowConcreteTypeSpecialization::create(ConstraintSystem &cs, Type concreteTy,
2849+
ConstraintLocator *locator) {
2850+
return new (cs.getAllocator())
2851+
AllowConcreteTypeSpecialization(cs, concreteTy, locator);
2852+
}
2853+
2854+
bool IgnoreGenericSpecializationArityMismatch::diagnose(
2855+
const Solution &solution, bool asNote) const {
2856+
InvalidTypeSpecializationArity failure(solution, D, NumParams, NumArgs,
2857+
HasParameterPack, getLocator());
2858+
return failure.diagnose(asNote);
2859+
}
2860+
2861+
IgnoreGenericSpecializationArityMismatch *
2862+
IgnoreGenericSpecializationArityMismatch::create(ConstraintSystem &cs,
2863+
ValueDecl *decl,
2864+
unsigned numParams,
2865+
unsigned numArgs,
2866+
bool hasParameterPack,
2867+
ConstraintLocator *locator) {
2868+
return new (cs.getAllocator()) IgnoreGenericSpecializationArityMismatch(
2869+
cs, decl, numParams, numArgs, hasParameterPack, locator);
2870+
}

lib/Sema/CSSimplify.cpp

Lines changed: 48 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -13598,21 +13598,41 @@ ConstraintSystem::simplifyExplicitGenericArgumentsConstraint(
1359813598
}
1359913599

1360013600
decl = overloadChoice.getDecl();
13601+
1360113602
auto openedOverloadTypes = getOpenedTypes(overloadLocator);
1360213603
openedTypes.append(openedOverloadTypes.begin(), openedOverloadTypes.end());
1360313604
}
1360413605

13605-
auto genericContext = decl->getAsGenericContext();
13606-
if (!genericContext)
13606+
std::function<GenericParamList *(ValueDecl *)> getGenericParams =
13607+
[&](ValueDecl *decl) -> GenericParamList * {
13608+
auto genericContext = decl->getAsGenericContext();
13609+
if (!genericContext)
13610+
return nullptr;
13611+
13612+
auto genericParams = genericContext->getGenericParams();
13613+
if (!genericParams) {
13614+
// If declaration is a non-generic typealias, let's point
13615+
// to the underlying generic declaration.
13616+
if (auto *TA = dyn_cast<TypeAliasDecl>(decl)) {
13617+
if (auto *UGT = TA->getUnderlyingType()->getAs<AnyGenericType>())
13618+
return getGenericParams(UGT->getDecl());
13619+
}
13620+
}
13621+
13622+
return genericParams;
13623+
};
13624+
13625+
if (!decl->getAsGenericContext())
1360713626
return SolutionKind::Error;
1360813627

13609-
auto genericParams = genericContext->getGenericParams();
13610-
if (!genericParams || genericParams->size() == 0) {
13628+
auto genericParams = getGenericParams(decl);
13629+
if (!genericParams) {
1361113630
// FIXME: Record an error here that we're ignoring the parameters.
1361213631
return SolutionKind::Solved;
1361313632
}
1361413633

1361513634
// Map the generic parameters we have over to their opened types.
13635+
bool hasParameterPack = false;
1361613636
SmallVector<Type, 2> openedGenericParams;
1361713637
auto genericParamDepth = genericParams->getParams()[0]->getDepth();
1361813638
for (const auto &openedType : openedTypes) {
@@ -13634,19 +13654,38 @@ ConstraintSystem::simplifyExplicitGenericArgumentsConstraint(
1363413654

1363513655
auto *expansion = PackExpansionType::get(patternType, shapeType);
1363613656
openedGenericParams.push_back(expansion);
13657+
hasParameterPack = true;
1363713658
} else {
1363813659
openedGenericParams.push_back(Type(openedType.second));
1363913660
}
1364013661
}
1364113662
}
13663+
13664+
if (openedGenericParams.empty()) {
13665+
if (!shouldAttemptFixes())
13666+
return SolutionKind::Error;
13667+
13668+
return recordFix(AllowConcreteTypeSpecialization::create(
13669+
*this, type1, getConstraintLocator(locator)))
13670+
? SolutionKind::Error
13671+
: SolutionKind::Solved;
13672+
}
13673+
1364213674
assert(openedGenericParams.size() == genericParams->size());
1364313675

1364413676
// Match the opened generic parameters to the specialized arguments.
1364513677
auto specializedArgs = type2->castTo<PackType>()->getElementTypes();
1364613678
PackMatcher matcher(openedGenericParams, specializedArgs, getASTContext(),
1364713679
isPackExpansionType);
13648-
if (matcher.match())
13649-
return SolutionKind::Error;
13680+
if (matcher.match()) {
13681+
if (!shouldAttemptFixes())
13682+
return SolutionKind::Error;
13683+
13684+
auto *fix = IgnoreGenericSpecializationArityMismatch::create(
13685+
*this, decl, openedGenericParams.size(), specializedArgs.size(),
13686+
hasParameterPack, getConstraintLocator(locator));
13687+
return recordFix(fix) ? SolutionKind::Error : SolutionKind::Solved;
13688+
}
1365013689

1365113690
// Bind the opened generic parameters to the specialization arguments.
1365213691
for (const auto &pair : matcher.pairs) {
@@ -14746,7 +14785,9 @@ ConstraintSystem::SolutionKind ConstraintSystem::simplifyFixConstraint(
1474614785
case FixKind::MacroMissingPound:
1474714786
case FixKind::AllowGlobalActorMismatch:
1474814787
case FixKind::AllowAssociatedValueMismatch:
14749-
case FixKind::GenericArgumentsMismatch: {
14788+
case FixKind::GenericArgumentsMismatch:
14789+
case FixKind::AllowConcreteTypeSpecialization:
14790+
case FixKind::IgnoreGenericSpecializationArityMismatch: {
1475014791
return recordFix(fix) ? SolutionKind::Error : SolutionKind::Solved;
1475114792
}
1475214793
case FixKind::IgnoreInvalidASTNode: {

test/Macros/macro_and_typealias.swift

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
// REQUIRES: swift_swift_parser, executable_test
2+
3+
// RUN: %empty-directory(%t)
4+
// RUN: %host-build-swift -swift-version 5 -emit-library -o %t/%target-library-name(MacroDefinition) -module-name=MacroDefinition %S/Inputs/variadic_macros.swift -g -no-toolchain-stdlib-rpath
5+
// RUN: %target-typecheck-verify-swift -disable-availability-checking -swift-version 5 -load-plugin-library %t/%target-library-name(MacroDefinition) -module-name MacroUser -DTEST_DIAGNOSTICS -swift-version 5
6+
7+
@freestanding(expression) public macro Print<each Value>(_ value: repeat each Value) = #externalMacro(module: "MacroDefinition", type: "PrintMacro")
8+
@freestanding(expression) public macro OtherPrint<each Value>(_ value: repeat each Value) = #externalMacro(module: "MacroDefinition", type: "PrintMacro")
9+
@freestanding(expression) public macro ConcretePrint(_ value: Any) = #externalMacro(module: "MacroDefinition", type: "PrintMacro")
10+
@freestanding(expression) public macro MultiPrint(_ value: Any) = #externalMacro(module: "MacroDefinition", type: "PrintMacro")
11+
12+
public struct Printer<Value> {
13+
init(_: (Value) -> Void) {}
14+
}
15+
16+
public struct MultiPrinter<T, U> {
17+
// expected-note@-1 {{'T' declared as parameter to type 'MultiPrinter'}}
18+
// expected-note@-2 {{'U' declared as parameter to type 'MultiPrinter'}}
19+
}
20+
21+
typealias Print = Printer
22+
typealias OtherPrint<T> = Printer<T>
23+
typealias ConcretePrint = Printer<Any>
24+
typealias MultiPrint = MultiPrinter
25+
26+
struct Test {
27+
struct Object {
28+
var prop: Int
29+
}
30+
31+
func test() {
32+
let _ = Print<Object> { // Ok
33+
compute(root: $0, \.prop)
34+
}
35+
36+
let _ = Print<Object, Int> {
37+
// expected-error@-1 {{generic type 'Print' specialized with too many type parameters (got 2, but expected 1)}}
38+
}
39+
40+
let _ = OtherPrint<Object> { // Ok
41+
compute(root: $0, \.prop)
42+
}
43+
44+
let _ = ConcretePrint<Object> { // expected-error {{cannot specialize non-generic type 'ConcretePrint' (aka 'Printer<Any>')}}
45+
compute(root: $0, \.prop) // expected-error {{value of type 'Any' has no member 'prop'}}
46+
// expected-note@-1 {{cast 'Any' to 'AnyObject' or use 'as!' to force downcast to a more specific type to access members}}
47+
}
48+
49+
let _ = MultiPrint<Int>()
50+
// expected-error@-1 {{generic type 'MultiPrint' specialized with too few type parameters (got 1, but expected 2)}}
51+
// expected-error@-2 {{generic parameter 'T' could not be inferred}}
52+
// expected-error@-3 {{generic parameter 'U' could not be inferred}}
53+
}
54+
55+
func compute<R, V>(root: R, _: KeyPath<R, V>) {}
56+
}

test/Macros/macros_diagnostics.swift

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -96,8 +96,7 @@ macro genericDeclMacro<T: Numeric, U: Numeric>(_ x: T, _ y: U)
9696
// expected-note @-2 {{where 'U' = 'String'}}
9797

9898
func testDiags(a: Int, b: Int) {
99-
// FIXME: Bad diagnostic.
100-
let s = #stringify<Int, Int>(a + b) // expected-error{{type of expression is ambiguous without a type annotation}}
99+
let s = #stringify<Int, Int>(a + b) // expected-error{{generic type 'stringify' specialized with too many type parameters (got 2, but expected 1)}}
101100

102101
_ = #stringify()
103102
// expected-error@-1{{missing argument for parameter #1 in macro expansion}}

0 commit comments

Comments
 (0)