Skip to content

Commit c50263c

Browse files
authored
Merge pull request #66971 from xedin/fix-specialization-issues
[ConstraintSystem] Fix a couple of issues related to generic specialization
2 parents 83ccdbb + de729e2 commit c50263c

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 {
@@ -3650,6 +3657,69 @@ class AllowInvalidMemberReferenceInInitAccessor final : public ConstraintFix {
36503657
}
36513658
};
36523659

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

lib/Sema/CSDiagnostics.cpp

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9164,3 +9164,14 @@ bool InvalidMemberReferenceWithinInitAccessor::diagnoseAsError() {
91649164
emitDiagnostic(diag::init_accessor_invalid_member_ref, MemberName);
91659165
return true;
91669166
}
9167+
9168+
bool ConcreteTypeSpecialization::diagnoseAsError() {
9169+
emitDiagnostic(diag::not_a_generic_type, ConcreteType);
9170+
return true;
9171+
}
9172+
9173+
bool InvalidTypeSpecializationArity::diagnoseAsError() {
9174+
emitDiagnostic(diag::type_parameter_count_mismatch, D->getBaseIdentifier(),
9175+
NumParams, NumArgs, NumArgs < NumParams, HasParameterPack);
9176+
return true;
9177+
}

lib/Sema/CSDiagnostics.h

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3051,6 +3051,50 @@ class InvalidMemberReferenceWithinInitAccessor final
30513051
bool diagnoseAsError() override;
30523052
};
30533053

3054+
/// Diagnose attempts to specialize a concrete type or its alias:
3055+
///
3056+
/// \code
3057+
/// struct Test {}
3058+
/// typealias X = Test
3059+
///
3060+
/// _ = X<Int>() // error
3061+
/// \endcode
3062+
class ConcreteTypeSpecialization final : public FailureDiagnostic {
3063+
Type ConcreteType;
3064+
3065+
public:
3066+
ConcreteTypeSpecialization(const Solution &solution, Type concreteTy,
3067+
ConstraintLocator *locator)
3068+
: FailureDiagnostic(solution, locator),
3069+
ConcreteType(resolveType(concreteTy)) {}
3070+
3071+
bool diagnoseAsError() override;
3072+
};
3073+
3074+
/// Diagnose attempts to specialize with invalid number of generic arguments:
3075+
///
3076+
/// \code
3077+
/// struct Test<T, U> {}
3078+
///
3079+
/// _ = Test<Int>() // error
3080+
/// \endcode
3081+
class InvalidTypeSpecializationArity final : public FailureDiagnostic {
3082+
ValueDecl *D;
3083+
unsigned NumParams;
3084+
unsigned NumArgs;
3085+
bool HasParameterPack;
3086+
3087+
public:
3088+
InvalidTypeSpecializationArity(const Solution &solution, ValueDecl *decl,
3089+
unsigned numParams, unsigned numArgs,
3090+
bool hasParameterPack,
3091+
ConstraintLocator *locator)
3092+
: FailureDiagnostic(solution, locator), D(decl), NumParams(numParams),
3093+
NumArgs(numArgs), HasParameterPack(hasParameterPack) {}
3094+
3095+
bool diagnoseAsError() override;
3096+
};
3097+
30543098
} // end namespace constraints
30553099
} // end namespace swift
30563100

lib/Sema/CSFix.cpp

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2829,3 +2829,34 @@ AllowInvalidMemberReferenceInInitAccessor::create(ConstraintSystem &cs,
28292829
return new (cs.getAllocator())
28302830
AllowInvalidMemberReferenceInInitAccessor(cs, memberName, locator);
28312831
}
2832+
2833+
bool AllowConcreteTypeSpecialization::diagnose(const Solution &solution,
2834+
bool asNote) const {
2835+
ConcreteTypeSpecialization failure(solution, ConcreteType, getLocator());
2836+
return failure.diagnose(asNote);
2837+
}
2838+
2839+
AllowConcreteTypeSpecialization *
2840+
AllowConcreteTypeSpecialization::create(ConstraintSystem &cs, Type concreteTy,
2841+
ConstraintLocator *locator) {
2842+
return new (cs.getAllocator())
2843+
AllowConcreteTypeSpecialization(cs, concreteTy, locator);
2844+
}
2845+
2846+
bool IgnoreGenericSpecializationArityMismatch::diagnose(
2847+
const Solution &solution, bool asNote) const {
2848+
InvalidTypeSpecializationArity failure(solution, D, NumParams, NumArgs,
2849+
HasParameterPack, getLocator());
2850+
return failure.diagnose(asNote);
2851+
}
2852+
2853+
IgnoreGenericSpecializationArityMismatch *
2854+
IgnoreGenericSpecializationArityMismatch::create(ConstraintSystem &cs,
2855+
ValueDecl *decl,
2856+
unsigned numParams,
2857+
unsigned numArgs,
2858+
bool hasParameterPack,
2859+
ConstraintLocator *locator) {
2860+
return new (cs.getAllocator()) IgnoreGenericSpecializationArityMismatch(
2861+
cs, decl, numParams, numArgs, hasParameterPack, locator);
2862+
}

lib/Sema/CSSimplify.cpp

Lines changed: 48 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -13584,21 +13584,41 @@ ConstraintSystem::simplifyExplicitGenericArgumentsConstraint(
1358413584
}
1358513585

1358613586
decl = overloadChoice.getDecl();
13587+
1358713588
auto openedOverloadTypes = getOpenedTypes(overloadLocator);
1358813589
openedTypes.append(openedOverloadTypes.begin(), openedOverloadTypes.end());
1358913590
}
1359013591

13591-
auto genericContext = decl->getAsGenericContext();
13592-
if (!genericContext)
13592+
std::function<GenericParamList *(ValueDecl *)> getGenericParams =
13593+
[&](ValueDecl *decl) -> GenericParamList * {
13594+
auto genericContext = decl->getAsGenericContext();
13595+
if (!genericContext)
13596+
return nullptr;
13597+
13598+
auto genericParams = genericContext->getGenericParams();
13599+
if (!genericParams) {
13600+
// If declaration is a non-generic typealias, let's point
13601+
// to the underlying generic declaration.
13602+
if (auto *TA = dyn_cast<TypeAliasDecl>(decl)) {
13603+
if (auto *UGT = TA->getUnderlyingType()->getAs<AnyGenericType>())
13604+
return getGenericParams(UGT->getDecl());
13605+
}
13606+
}
13607+
13608+
return genericParams;
13609+
};
13610+
13611+
if (!decl->getAsGenericContext())
1359313612
return SolutionKind::Error;
1359413613

13595-
auto genericParams = genericContext->getGenericParams();
13596-
if (!genericParams || genericParams->size() == 0) {
13614+
auto genericParams = getGenericParams(decl);
13615+
if (!genericParams) {
1359713616
// FIXME: Record an error here that we're ignoring the parameters.
1359813617
return SolutionKind::Solved;
1359913618
}
1360013619

1360113620
// Map the generic parameters we have over to their opened types.
13621+
bool hasParameterPack = false;
1360213622
SmallVector<Type, 2> openedGenericParams;
1360313623
auto genericParamDepth = genericParams->getParams()[0]->getDepth();
1360413624
for (const auto &openedType : openedTypes) {
@@ -13620,19 +13640,38 @@ ConstraintSystem::simplifyExplicitGenericArgumentsConstraint(
1362013640

1362113641
auto *expansion = PackExpansionType::get(patternType, shapeType);
1362213642
openedGenericParams.push_back(expansion);
13643+
hasParameterPack = true;
1362313644
} else {
1362413645
openedGenericParams.push_back(Type(openedType.second));
1362513646
}
1362613647
}
1362713648
}
13649+
13650+
if (openedGenericParams.empty()) {
13651+
if (!shouldAttemptFixes())
13652+
return SolutionKind::Error;
13653+
13654+
return recordFix(AllowConcreteTypeSpecialization::create(
13655+
*this, type1, getConstraintLocator(locator)))
13656+
? SolutionKind::Error
13657+
: SolutionKind::Solved;
13658+
}
13659+
1362813660
assert(openedGenericParams.size() == genericParams->size());
1362913661

1363013662
// Match the opened generic parameters to the specialized arguments.
1363113663
auto specializedArgs = type2->castTo<PackType>()->getElementTypes();
1363213664
PackMatcher matcher(openedGenericParams, specializedArgs, getASTContext(),
1363313665
isPackExpansionType);
13634-
if (matcher.match())
13635-
return SolutionKind::Error;
13666+
if (matcher.match()) {
13667+
if (!shouldAttemptFixes())
13668+
return SolutionKind::Error;
13669+
13670+
auto *fix = IgnoreGenericSpecializationArityMismatch::create(
13671+
*this, decl, openedGenericParams.size(), specializedArgs.size(),
13672+
hasParameterPack, getConstraintLocator(locator));
13673+
return recordFix(fix) ? SolutionKind::Error : SolutionKind::Solved;
13674+
}
1363613675

1363713676
// Bind the opened generic parameters to the specialization arguments.
1363813677
for (const auto &pair : matcher.pairs) {
@@ -14732,7 +14771,9 @@ ConstraintSystem::SolutionKind ConstraintSystem::simplifyFixConstraint(
1473214771
case FixKind::MacroMissingPound:
1473314772
case FixKind::AllowGlobalActorMismatch:
1473414773
case FixKind::AllowAssociatedValueMismatch:
14735-
case FixKind::GenericArgumentsMismatch: {
14774+
case FixKind::GenericArgumentsMismatch:
14775+
case FixKind::AllowConcreteTypeSpecialization:
14776+
case FixKind::IgnoreGenericSpecializationArityMismatch: {
1473614777
return recordFix(fix) ? SolutionKind::Error : SolutionKind::Solved;
1473714778
}
1473814779
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)