Skip to content

Commit 9d954f2

Browse files
authored
Merge pull request #5857 from DougGregor/req-env-same-type
2 parents 85296ef + 4a2a710 commit 9d954f2

File tree

6 files changed

+122
-3
lines changed

6 files changed

+122
-3
lines changed

include/swift/AST/DiagnosticsSema.def

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1296,6 +1296,10 @@ ERROR(objc_runtime_visible_cannot_conform_to_objc_protocol,none,
12961296
ERROR(protocol_has_missing_requirements,none,
12971297
"type %0 cannot conform to protocol %1 because it has requirements that "
12981298
"cannot be satisfied", (Type, Type))
1299+
ERROR(requirement_restricts_self,none,
1300+
"%0 requirement %1 cannot add constraint '%2%select{:|:| ==|:}3 %4' on "
1301+
"'Self'",
1302+
(DescriptiveDeclKind, DeclName, StringRef, unsigned, StringRef))
12991303
ERROR(witness_argument_name_mismatch,none,
13001304
"%select{method|initializer}0 %1 has different argument names from those "
13011305
"required by protocol %2 (%3)", (bool, DeclName, Type, DeclName))
@@ -1317,7 +1321,6 @@ ERROR(witness_requires_dynamic_self,none,
13171321
"method %0 in non-final class %1 must return `Self` to conform to "
13181322
"protocol %2",
13191323
(DeclName, Type, Type))
1320-
13211324
ERROR(witness_not_accessible_proto,none,
13221325
"%select{initializer %1|method %1|%select{|setter for }2property %1"
13231326
"|subscript%select{| setter}2}0 must be declared "

lib/AST/ArchetypeBuilder.cpp

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -975,6 +975,8 @@ bool ArchetypeBuilder::addConformanceRequirement(PotentialArchetype *PAT,
975975
bool ArchetypeBuilder::addSuperclassRequirement(PotentialArchetype *T,
976976
Type Superclass,
977977
RequirementSource Source) {
978+
T = T->getRepresentative();
979+
978980
if (Superclass->hasArchetype()) {
979981
// Map contextual type to interface type.
980982
// FIXME: There might be a better way to do this.
@@ -1238,7 +1240,11 @@ bool ArchetypeBuilder::addSameTypeRequirementBetweenArchetypes(
12381240
for (auto equiv : T2->EquivalenceClass)
12391241
T1->EquivalenceClass.push_back(equiv);
12401242

1241-
// FIXME: superclass requirements!
1243+
// Superclass requirements.
1244+
if (T2->Superclass) {
1245+
addSuperclassRequirement(T1, T2->getSuperclass(),
1246+
T2->getSuperclassSource());
1247+
}
12421248

12431249
// Add all of the protocol conformance requirements of T2 to T1.
12441250
for (auto conforms : T2->ConformsTo) {

lib/Sema/TypeCheckGeneric.cpp

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -458,6 +458,24 @@ static Type getResultType(TypeChecker &TC, FuncDecl *fn, Type resultType) {
458458
return resultType;
459459
}
460460

461+
/// Determine whether the given type is \c Self, an associated type of \c Self,
462+
/// or a concrete type.
463+
static bool isSelfDerivedOrConcrete(Type type) {
464+
// Check for a concrete type.
465+
if (!type->hasTypeParameter())
466+
return true;
467+
468+
// Unwrap dependent member types.
469+
while (auto depMem = type->getAs<DependentMemberType>()) {
470+
type = depMem->getBase();
471+
}
472+
473+
if (auto gp = type->getAs<GenericTypeParamType>())
474+
return gp->getDepth() == 0 && gp->getIndex() == 0;
475+
476+
return false;
477+
}
478+
461479
GenericSignature *
462480
TypeChecker::validateGenericFuncSignature(AbstractFunctionDecl *func) {
463481
bool invalid = false;
@@ -493,6 +511,34 @@ TypeChecker::validateGenericFuncSignature(AbstractFunctionDecl *func) {
493511
// the type of the generic function.
494512
auto sig = builder.getGenericSignature();
495513

514+
// For a generic requirement in a protocol, make sure that the requirement
515+
// set didn't add any requirements to Self or its associated types.
516+
if (!invalid && func->getGenericParams() &&
517+
isa<ProtocolDecl>(func->getDeclContext())) {
518+
auto proto = cast<ProtocolDecl>(func->getDeclContext());
519+
for (auto req : sig->getRequirements()) {
520+
// If one of the types in the requirement is dependent on a non-Self
521+
// type parameter, this requirement is okay.
522+
if (!isSelfDerivedOrConcrete(req.getFirstType()) ||
523+
!isSelfDerivedOrConcrete(req.getSecondType()))
524+
continue;
525+
526+
// The conformance of 'Self' to the protocol is okay.
527+
if (req.getKind() == RequirementKind::Conformance &&
528+
req.getSecondType()->getAs<ProtocolType>()->getDecl() == proto &&
529+
req.getFirstType()->is<GenericTypeParamType>())
530+
continue;
531+
532+
diagnose(func, diag::requirement_restricts_self,
533+
func->getDescriptiveKind(), func->getFullName(),
534+
req.getFirstType().getString(),
535+
static_cast<unsigned>(req.getKind()),
536+
req.getSecondType().getString());
537+
538+
invalid = true;
539+
}
540+
}
541+
496542
// Debugging of the archetype builder and generic signature generation.
497543
if (Context.LangOpts.DebugGenericSignatures) {
498544
func->dumpRef(llvm::errs());

lib/Sema/TypeCheckProtocol.cpp

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1110,8 +1110,14 @@ RequirementEnvironment::RequirementEnvironment(
11101110
auto first = reqReq.getFirstType().subst(reqToSyntheticEnvMap);
11111111
auto second = reqReq.getSecondType().subst(reqToSyntheticEnvMap);
11121112

1113+
// FIXME: We really want to check hasTypeParameter here, but the
1114+
// ArchetypeBuilder isn't ready for that.
11131115
if (!first->isTypeParameter()) {
1114-
assert(second->isTypeParameter());
1116+
// When the second is not a type parameter either, drop the requirement.
1117+
// If the types were different, this requirement will be unsatisfiable.
1118+
if (!second->isTypeParameter()) continue;
1119+
1120+
// Put the type parameter first.
11151121
std::swap(first, second);
11161122
}
11171123

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
// RUN: %target-parse-verify-swift
2+
3+
protocol P {
4+
associatedtype A
5+
associatedtype B
6+
7+
func f<T: P>(_: T) where T.A == Self.A, T.A == Self.B // expected-error{{instance method requirement 'f' cannot add constraint 'Self.A == Self.B' on 'Self'}}
8+
}
9+
10+
extension P {
11+
func f<T: P>(_: T) where T.A == Self.A, T.A == Self.B { }
12+
}
13+
14+
struct X : P {
15+
typealias A = X
16+
typealias B = Int
17+
}
18+
19+
protocol P2 {
20+
associatedtype A
21+
22+
func f<T: P2>(_: T) where T.A == Self.A, T.A: P2 // expected-error{{instance method requirement 'f' cannot add constraint 'Self.A: P2' on 'Self'}}
23+
}
24+
25+
class C { }
26+
27+
protocol P3 {
28+
associatedtype A
29+
30+
func f<T: P3>(_: T) where T.A == Self.A, T.A: C // expected-error{{instance method requirement 'f' cannot add constraint 'Self.A: C' on 'Self'}}
31+
func g<T: P3>(_: T) where T.A: C, T.A == Self.A // expected-error{{instance method requirement 'g' cannot add constraint 'Self.A: C' on 'Self'}}
32+
}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
// RUN: not %target-swift-frontend %s
2+
3+
typealias Element<S: Sequence> = S.Iterator.Element
4+
5+
protocol StringProtocol {
6+
associatedtype Content
7+
associatedtype UnicodeScalars : BidirectionalCollection
8+
var unicodeScalars : UnicodeScalars { get }
9+
10+
mutating func append<T: StringProtocol>(other: T)
11+
where Content == T.Content,
12+
Element<UnicodeScalars> == Element<T.UnicodeScalars>,
13+
Element<T.UnicodeScalars> == UnicodeScalar
14+
}
15+
16+
struct X : StringProtocol {
17+
typealias Content = Int
18+
var unicodeScalars: [UnicodeScalar]
19+
20+
mutating func append<T: StringProtocol>(other: T)
21+
where Content == T.Content,
22+
T.UnicodeScalars.Iterator.Element == UnicodeScalar
23+
{
24+
print(other.unicodeScalars.first!)
25+
}
26+
}

0 commit comments

Comments
 (0)