Skip to content

Small Sema fixes #6406

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 6 commits into from
Dec 20, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions lib/AST/ArchetypeBuilder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1993,6 +1993,17 @@ static void collectRequirements(ArchetypeBuilder &builder,
if (auto concreteTy = type.dyn_cast<Type>()) {
// Maybe we were equated to a concrete type...
repTy = concreteTy;

// Drop requirements involving concrete types containing
// unresolved associated types.
if (repTy.findIf([](Type t) -> bool {
if (auto *depTy = dyn_cast<DependentMemberType>(t.getPointer()))
if (depTy->getAssocType() == nullptr)
return true;
return false;
})) {
return;
}
} else {
// ...or to a dependent type.
repTy = type.get<ArchetypeBuilder::PotentialArchetype *>()
Expand Down
8 changes: 5 additions & 3 deletions lib/AST/Module.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -610,16 +610,18 @@ TypeBase::gatherAllSubstitutions(Module *module,
llvm_unreachable("Not a nominal or bound generic type");
}

auto *genericEnv = gpContext->getGenericEnvironmentOfContext();

// Add forwarding substitutions from the outer context if we have
// a type nested inside a generic function.
auto *parentDC = gpContext;
while (parentDC->isTypeContext())
parentDC = parentDC->getParent();
if (auto *outerEnv = parentDC->getGenericEnvironmentOfContext()) {
for (auto gp : outerEnv->getGenericParams()) {
if (auto *outerSig = parentDC->getGenericSignatureOfContext()) {
for (auto gp : outerSig->getGenericParams()) {
auto result = substitutions.insert(
{gp->getCanonicalType()->castTo<GenericTypeParamType>(),
outerEnv->mapTypeIntoContext(gp)});
genericEnv->mapTypeIntoContext(gp)});
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Whoops, nice catch!

assert(result.second);
}
}
Expand Down
4 changes: 4 additions & 0 deletions lib/Sema/ITCDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,10 @@ void IterativeTypeChecker::processResolveInheritedClauseEntry(
&unsatisfiedDependency)) {
inherited->setInvalidType(getASTContext());
}

auto type = inherited->getType();
if (!type.isNull())
inherited->setType(dc->mapTypeOutOfContext(type));
}

bool IterativeTypeChecker::breakCycleForResolveInheritedClauseEntry(
Expand Down
4 changes: 3 additions & 1 deletion lib/Sema/TypeCheckDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3464,6 +3464,7 @@ class DeclChecker : public DeclVisitor<DeclChecker> {
: TC(TC), IsFirstPass(IsFirstPass), IsSecondPass(IsSecondPass) {}

void visit(Decl *decl) {
PrettyStackTraceDecl StackTrace("type-checking", decl);

DeclVisitor<DeclChecker>::visit(decl);

Expand Down Expand Up @@ -6570,7 +6571,6 @@ bool TypeChecker::isAvailabilitySafeForConformance(
}

void TypeChecker::typeCheckDecl(Decl *D, bool isFirstPass) {
PrettyStackTraceDecl StackTrace("type-checking", D);
checkForForbiddenPrefix(D);
bool isSecondPass =
!isFirstPass && D->getDeclContext()->isModuleScopeContext();
Expand Down Expand Up @@ -6756,6 +6756,8 @@ void TypeChecker::validateDecl(ValueDecl *D) {
if (D->isBeingValidated())
return;

PrettyStackTraceDecl StackTrace("validating", D);

if (hasEnabledForbiddenTypecheckPrefix())
checkForForbiddenPrefix(D);

Expand Down
4 changes: 3 additions & 1 deletion lib/Sema/TypeCheckNameLookup.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -340,7 +340,9 @@ LookupTypeResult TypeChecker::lookupMemberType(DeclContext *dc,
// existential type, because we have no way to represent such types.
//
// This is diagnosed further on down in resolveNestedIdentTypeComponent().
if (type->isExistentialType()) {
if (type->isExistentialType() &&
(isa<TypeAliasDecl>(typeDecl) ||
isa<AssociatedTypeDecl>(typeDecl))) {
auto memberType = typeDecl->getInterfaceType()->getRValueInstanceType();

if (memberType->hasTypeParameter()) {
Expand Down
49 changes: 26 additions & 23 deletions lib/Sema/TypeCheckType.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -221,38 +221,41 @@ findDeclContextForType(TypeChecker &TC,

bool needsBaseType = (ownerDC->isTypeContext() &&
!isa<GenericTypeParamDecl>(typeDecl));
NominalTypeDecl *ownerNominal = nullptr;
if (needsBaseType) {
ownerNominal = ownerDC->getAsNominalTypeOrNominalTypeExtensionContext();
NominalTypeDecl *ownerNominal =
ownerDC->getAsNominalTypeOrNominalTypeExtensionContext();

// We might have an invalid extension that didn't resolve.
if (ownerNominal == nullptr)
return std::make_tuple(nullptr, nullptr, false);
}
// We might have an invalid extension that didn't resolve.
if (needsBaseType && ownerNominal == nullptr)
return std::make_tuple(nullptr, nullptr, false);

// First, check for containment in one of our parent contexts.
for (auto parentDC = fromDC; !parentDC->isModuleContext();
parentDC = parentDC->getParent()) {
auto parentNominal =
parentDC->getAsNominalTypeOrNominalTypeExtensionContext();

// If we're not computing a base type, we just have to check for
// containment in one of our parent contexts.
if (!needsBaseType) {
if (ownerDC == parentDC)
return std::make_tuple(ownerDC, nullptr, true);
if (ownerDC == parentDC)
return std::make_tuple(parentDC, parentNominal, true);

// FIXME: Horrible hack. Don't allow us to reference a generic parameter
// or from a context outside a ProtocolDecl.
if (isa<ProtocolDecl>(parentDC) && isa<GenericTypeParamDecl>(typeDecl))
return std::make_tuple(nullptr, nullptr, false);
// FIXME: Horrible hack. Don't allow us to reference a generic parameter
// from a context outside a ProtocolDecl.
if (isa<ProtocolDecl>(parentDC) && isa<GenericTypeParamDecl>(typeDecl))
return std::make_tuple(nullptr, nullptr, false);
}

continue;
}
if (!needsBaseType) {
assert(false && "Should have found non-type context by now");
return std::make_tuple(nullptr, nullptr, false);
}

// Now, search the supertypes or refined protocols of each parent
// context.
for (auto parentDC = fromDC; !parentDC->isModuleContext();
parentDC = parentDC->getParent()) {
// For the next steps we need our parentDC to be a type context
if (!parentDC->isTypeContext())
continue;

// Search the type of this context and its supertypes (if its a
// class) or refined protocols (if its a protocol).
llvm::SmallPtrSet<const NominalTypeDecl *, 8> visited;
llvm::SmallVector<const NominalTypeDecl *, 8> stack;

Expand Down Expand Up @@ -314,9 +317,9 @@ findDeclContextForType(TypeChecker &TC,
}
}

// FIXME: Horrible hack. Don't allow us to reference an associated type
// from a context outside a ProtocolDecl.
if (isa<ProtocolDecl>(parentDC) && isa<AssociatedTypeDecl>(typeDecl))
// FIXME: Horrible hack. Don't allow us to reference a generic parameter
// or associated type from a context outside a ProtocolDecl.
if (isa<ProtocolDecl>(parentDC) && isa<AbstractTypeParamDecl>(typeDecl))
return std::make_tuple(nullptr, nullptr, false);
}

Expand Down
10 changes: 10 additions & 0 deletions test/Generics/invalid.swift
Original file line number Diff line number Diff line change
Expand Up @@ -79,3 +79,13 @@ func takesAny(_ a: Any) {}
func badDiagnostic3() {
takesAny(Deli.self) // expected-error {{argument type 'Deli<_>.Type' does not conform to expected type 'Any'}}
}

// Crash with missing nested type inside concrete type
class OuterGeneric<T> {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@DougGregor do we have any radars for this one? :)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I bet we do... somewhere!

class InnerGeneric<U> where U:OuterGeneric<T.NoSuchType> {
// expected-error@-1 {{'NoSuchType' is not a member type of 'T'}}
func method() {
_ = method
}
}
}
13 changes: 13 additions & 0 deletions test/decl/nested/protocol.swift
Original file line number Diff line number Diff line change
Expand Up @@ -41,9 +41,22 @@ protocol Racoon {
}
}

enum SillyRawEnum : SillyProtocol.InnerClass {}
// expected-error@-1 {{raw type 'SillyProtocol.InnerClass' is not expressible by any literal}}
// expected-error@-2 {{'SillyRawEnum' declares raw type 'SillyProtocol.InnerClass', but does not conform to RawRepresentable and conformance could not be synthesized}}

protocol SillyProtocol {
class InnerClass<T> {} // expected-error {{type 'InnerClass' cannot be nested in protocol 'SillyProtocol'}}
}

enum OuterEnum {
protocol C {} // expected-error{{protocol 'C' cannot be nested inside another declaration}}
// expected-note@-1{{'C' previously declared here}}
case C(C) // expected-error{{invalid redeclaration of 'C'}}
}

class OuterClass<T> {
protocol InnerProtocol : OuterClass { }
// expected-error@-1{{protocol 'InnerProtocol' cannot be nested inside another declaration}}
// expected-error@-2{{non-class type 'InnerProtocol' cannot inherit from class 'OuterClass<T>'}}
}
12 changes: 12 additions & 0 deletions test/decl/nested/type_in_function.swift
Original file line number Diff line number Diff line change
Expand Up @@ -79,3 +79,15 @@ func f5<T, U>(x: T, y: U) {
typealias U = Int
}
}

// Issue with gatherAllSubstitutions().
struct OuterGenericStruct<A> {
class MiddleNonGenericClass {
func nonGenericFunction() {
class InnerGenericClass<T> : MiddleNonGenericClass {
// expected-error@-1 {{type 'InnerGenericClass' cannot be nested in generic function 'nonGenericFunction'}}
override init() { super.init() }
}
}
}
}
5 changes: 5 additions & 0 deletions test/decl/nested/type_in_type.swift
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,11 @@ class OuterGenericClass<T> {
super.init()
}
}

class Middle {
class Inner1<T> {}
class Inner2<T> : Middle where T: Inner1<Int> {}
}
}

// <rdar://problem/12895793>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
// See https://swift.org/LICENSE.txt for license information
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors

// RUN: not --crash %target-swift-frontend %s -typecheck
// RUN: not %target-swift-frontend %s -typecheck
// REQUIRES: asserts
class B<a>{
protocol c:a
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,6 @@
// See https://swift.org/LICENSE.txt for license information
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors

// RUN: not --crash %target-swift-frontend %s -emit-ir
// RUN: not %target-swift-frontend %s -emit-ir
// REQUIRES: asserts
protocol C{struct D:C{enum A{case J(f}typealias F=Self}typealias f typealias F
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,5 @@
// See https://swift.org/LICENSE.txt for license information
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors

// RUN: not --crash %target-swift-frontend %s -emit-ir
// RUN: not %target-swift-frontend %s -emit-ir
class B<T>{class a{var:{class B<T>:a