Skip to content

Commit 3dc4114

Browse files
committed
Sema: Fix crash when resolving bound generic type with unbound parent
Eg, if both Foo and Bar are generic, Foo.Bar<Int> would crash. This was introduced when I refactored the code a bit to combine the code path for nominal types and generic typealiases. I was a little too eager in merging them, because in fact the substitution-based approach doesn't work when the parent type is an unbound generic, which can occur in the nominal type case. Note that we skip validation of generic parameters when the parent type is an unbound generic. This is because there may be requirements relating the generic arguments of the parent type with the generic arguments of the nested type, and unless all arguments are known, we cannot check these requirements. For example: struct Outer<T : Collection> { struct Inner<U : Collection> where T.Element == U.Element { } } When Sema opens the unbound generic type by creating new type variables for each generic argument, it will also introduce constraints corresponding to each generic requirement. Therefore constraint system will eventually fail if the arguments are wrong. Fixes <https://bugs.swift.org/browse/SR-5600>, <rdar://problem/33655028>.
1 parent 9358671 commit 3dc4114

File tree

2 files changed

+38
-0
lines changed

2 files changed

+38
-0
lines changed

lib/Sema/TypeCheckType.cpp

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -481,6 +481,28 @@ Type TypeChecker::applyUnboundGenericArguments(
481481
// type.
482482
if (auto parentType = unboundType->getParent()) {
483483
if (parentType->hasUnboundGenericType()) {
484+
// If we're working with a nominal type declaration, just construct
485+
// a bound generic type without checking the generic arguments.
486+
if (auto *nominalDecl = dyn_cast<NominalTypeDecl>(decl)) {
487+
SmallVector<Type, 2> args;
488+
for (auto &genericArg : genericArgs) {
489+
// Propagate failure.
490+
if (validateType(genericArg, dc, options, resolver,
491+
unsatisfiedDependency))
492+
return ErrorType::get(Context);
493+
494+
auto substTy = genericArg.getType();
495+
496+
// Unsatisfied dependency case.
497+
if (!substTy)
498+
return nullptr;
499+
500+
args.push_back(substTy);
501+
}
502+
503+
return BoundGenericType::get(nominalDecl, parentType, args);
504+
}
505+
484506
assert(!resultType->hasTypeParameter());
485507
return resultType;
486508
}

test/decl/nested/type_in_type.swift

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -381,12 +381,28 @@ struct Claws<A: ExpressibleByCatLiteral> {
381381
struct Fangs<B: ExpressibleByDogLiteral> { }
382382
}
383383

384+
struct NotADog {}
385+
384386
func pets<T>(fur: T) -> Claws<Kitten>.Fangs<T> {
385387
return Claws<Kitten>.Fangs<T>()
386388
}
387389

390+
func something<T>() -> T { // expected-note {{in call to function 'something()'}}
391+
while true {}
392+
}
393+
388394
func test() {
389395
let _: Claws<Kitten>.Fangs<Puppy> = pets(fur: Puppy())
396+
397+
// <https://bugs.swift.org/browse/SR-5600>
398+
let _: Claws.Fangs<Puppy> = pets(fur: Puppy())
399+
let _: Claws.Fangs<Puppy> = Claws<Kitten>.Fangs()
400+
let _: Claws.Fangs<Puppy> = Claws.Fangs()
401+
// expected-error@-1 {{cannot convert value of type 'Claws<_>.Fangs<_>' to specified type 'Claws.Fangs<Puppy>'}}
402+
let _: Claws.Fangs<NotADog> = something()
403+
// expected-error@-1 {{generic parameter 'T' could not be inferred}} // FIXME: bad diagnostic
404+
_ = Claws.Fangs<NotADog>()
405+
// expected-error@-1 {{type 'NotADog' does not conform to protocol 'ExpressibleByDogLiteral'}}
390406
}
391407

392408
// https://bugs.swift.org/browse/SR-4379

0 commit comments

Comments
 (0)